ホームページ  >  記事  >  ウェブフロントエンド  >  Promise、async、await を理解する

Promise、async、await を理解する

hzc
hzc転載
2020-07-04 09:50:021861ブラウズ

前の記事では主に、同期と非同期、「実行スタック」、「メッセージ キュー」、そしてそれぞれから派生した「マクロ タスク」と「マイクロ タスク」について説明しました。それについてはあまり詳しくありませんが、次のリンクにアクセスしてください:

https://www.jianshu.com/p/61e7844e68d8

マクロ タスクとマイクロ タスクは両方とも、ajax を含めて非同期です。リクエストとタイミング。私たちは Promise について予備的に理解しており、それが非同期の問題を解決する方法であることを知っています。では、一般的に使用する方法は何ですか?

多くの知識ポイントが含まれるため、この記事では主にコールバック関数とプロミスについて話しましょう:

1. コールバック関数

先上代码:
function f2() {
    console.log('2222')
}
function f1(callback){
    console.log('111')
  setTimeout(function () {
    callback(); 
  }, 5000);
  console.log('3333')
}
f1(f2);

先看下打印值是:
111
3333
五秒后2222

は、メインスレッドの実行が終了した後、f2 関数が次のようになることと同等です。コールバック関数を通じて呼び出されます。これには何も問題はありません。ただし、次の例を見てください:

现在我们读取一个文件,fileReader就是一个异步请求

// 这个异步请求就是通过回调函数的方式获取的

var reader = new FileReader()
var file = input.files[0]
reader.readAsText(file, 'utf-8',function(err, data){
    if(err){
        console.log(err)
    } else {
        console.log(data)
    }
})

これで非常にうまく見えますが、ファイルのアップロードでエラーが発生した場合は、コールバックで判断する必要があります。このファイルの読み取りを終了すると、次のようになります。複数のファイルを読み取るには ファイルはどこにありますか?次のように書く必要があります:

读取完文件1之后再接着读取文件2、3

var reader = new FileReader()
var file = input.files[0]
reader.readAsText(file1, 'utf-8',function(err1, data1){
    if(err1){
        console.log(err1)
    } else {
        console.log(data1)
    }
    reader.readAsText(file2, 'utf-8',function(err2, data2){
        if(err2){
            console.log(err2)
        } else {
            console.log(data2)
        }
        reader.readAsText(file3, 'utf-8',function(err3, data3){
            if(err3){
                console.log(err3)
            } else {
                console.log(data3)
            }
        })
    })
})

このように書くと要件は達成できますが、このコードの可読性は比較的低く、見た目もそれほどエレガントではありません。これは、私たちがよく「コールバック地獄」と呼ぶものです。では、このネストされたコールバックを解読するにはどうすればよいでしょうか? ES6 は次のような Promise を提供します。

2. Promise

まず、Promise が文字通り何であるかを理解しましょう。 Promise はコミットメントと保証と言い換えることができます。この場所は次のように理解できます:

私のガールフレンドは私に何かをするよう頼んだのですが、私はまだそれを終えていませんが、私はあなたに結果があることを約束します。成功 (履行) または失敗 (拒否)、および待機状態 (保留)。

还是先上例子

let promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(2000) // 成功以后这个resolve会把成功的结果捕捉到
        // reject(2000) // 失败以后这个reject会把失败的结果捕捉到
    }, 1000)
    console.log(1111)
})

promise.then(res => {
    console.log(res) // then里面第一个参数就能拿到捕捉到的成功结果
}, err =>{
    console.log(res)// then里面第二个参数就能拿到捕捉到的失败结果
})

打印结果:

1111
2000(一秒以后)

1. then チェーン操作

Promise オブジェクトの then メソッドは新しい Promise オブジェクトを返すため、then メソッドはチェーンを通じて呼び出すことができます。

Thethen メソッドは 2 つの関数をパラメータとして受け取ります。最初のパラメータは Promise が正常に実行されたときのコールバックであり、2 番目のパラメータは Promise が実行に失敗したときのコールバックです。上の例はそれを非常に明確にしています。2 つのパラメータ失敗したコールバックをキャプチャします。

2 つの関数のうち 1 つだけが呼び出されます。この文はどう理解すればよいでしょうか?
あなたのガールフレンドは、トマトと卵のスープを作るようにあなたに頼みます。あなたは、それをするか、そうせずにテイクアウトを注文するかのどちらかです。第 3 の選択肢は絶対にありません。

関数の戻り値は、それまでに返される Promise オブジェクトの作成に使用されます。この文はどのように理解すべきでしょうか?まだ上記の例:

let promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(2000)
    }, 1000)
    console.log(1111)
})
promise.then(res => {
    console.log(res) // 这个地方会打印捕捉到的2000
    return res + 1000 // 这个函数的返回值,返回的就是这个promise对象捕捉到的成功的值
}).then(res => {
    console.log(res) //这个地方打印的就是上一个promise对象return的值
})

所以打印顺序应该是:

1111
2000
3000

今、 then が 2 つのパラメータを受け入れるのを見ました。1 つは成功したコールバックで、もう 1 つは失敗したコールバックです。それほどエレガントではないようです。then に加えて、promise も指定します。 catch メソッドを提供します。 :

2. キャッチ キャプチャ操作

このキャッチは、エラー コールバックをキャプチャするために特別に設計されています。まず例を見てみましょう:

let promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject(2000) // 失败以后这个reject会把失败的结果捕捉到
    }, 1000)
    console.log(1111)
})
promise.catch(res => {
    console.log(res) // catch里面就能拿到捕捉到的失败结果
})

打印结果:

1111
2000(一秒以后)

then と catch、promise にも次の 2 つの構文、all と Race を簡単に使用します:

3, all

さて、このような要件があります。3 つのインターフェイス A、B、 C. 3 つが必要です。すべてのインターフェイスが成功すると、4 番目のリクエストを開始できます。実装方法は?

連鎖呼び出し

let getInfoA = new Promise((resolve, reject) => {
    console.log('小A开始执行了')
    resolve()
}).then(res => {
    let getInfoB = new Promise((resolve, reject) => {
        console.log('小B开始执行了')
        resolve()
    }).then(res => {
        let getInfoC = new Promise((resolve, reject) => {
            console.log('小C开始执行了')
            resolve()
        }).then(res => {
            console.log('全都执行完了!')
        })
    })
})

これは 1 つの層の中に別の層があり、それほどエレガントではないようです

all

let getInfoA = new Promise((resolve, reject) => {
    console.log('小A开始执行了')
    resolve()
})
let getInfoB = new Promise((resolve, reject) => {
    console.log('小B开始执行了')
    resolve()
})
let getInfoC = new Promise((resolve, reject) => {
    console.log('小C开始执行了')
    resolve()
})
Promise.all([getInfoA, getInfoB, getInfoC]).then(res => {
   console.log('全都执行完了!')
})

Promise オブジェクトで構成される配列を次のように受け取りますparameters では、この配列内のすべての Promise オブジェクトのステータスが解決または拒否されると、 then メソッドが呼び出されます。とても完璧で、とてもエレガントです。

4、レース

今度は別の要件があり、これもインターフェイス A、B、C です。そのうちの 1 つが応答する限り、インターフェイス D を調整できます。それでは、それを実装する方法?

1. 従来のメソッド

let getInfoA = new Promise((resolve, reject) => {
    console.log('小A开始执行了')
    setTimeout((err => {
        resolve('小A最快')
    }),1000)
}).then(res =>{
    console.log(res)
})
let getInfoB = new Promise((resolve, reject) => {
    console.log('小B开始执行了')
    setTimeout((err => {
        resolve('小B最快')
    }),1001)
}).then(res =>{
    console.log(res)
})
let getInfoC = new Promise((resolve, reject) => {
    console.log('小C开始执行了')
    setTimeout((err => {
        resolve('小C最快')
    }),1002)
}).then(res =>{
    console.log(res)
})

打印结果

小A开始执行了
小B开始执行了
小C开始执行了
小A最快

このメソッドは 3 回記述する必要があり、それほどエレガントではないようです。race の書き方を見てみましょう。

2, Race

let getInfoA = new Promise((resolve, reject) => {
    console.log('小A开始执行了')
    setTimeout((err => {
        resolve('小A最快')
    }),1000)
})
let getInfoB = new Promise((resolve, reject) => {
    console.log('小B开始执行了')
    setTimeout((err => {
        resolve('小B最快')
    }),1001)
})
let getInfoC = new Promise((resolve, reject) => {
    console.log('小C开始执行了')
    setTimeout((err => {
        resolve('小C最快')
    }),1002)
})
Promise.race([getInfoA, getInfoB, getInfoC]).then(res => {
    console.log(res)
})

打印结果

小A开始执行了
小B开始执行了
小C开始执行了
小A最快

Promise.all と同様に、Promise.race は、Promise オブジェクトで構成される配列をパラメーターとして受け取ります。違いは、配列内の Promise オブジェクトの 1 つが存在する限り、 Promsie のステータスが解決済みまたは拒否に変わると、.then メソッドを呼び出すことができます。

Promise は ES6 で非同期問題を解決するために使われている手法で、現在広く使われており、例えば私たちがよく使う axios は Promise でカプセル化されており非常に便利です。

Promise に加えて、ES6 は究極のトリックである async と await も提供します。これら 2 つの知識ブロックは比較的大きいため、次の記事で説明します。

個人 WeChat 公開アカウント: ジェリーが何か言いたいことがあれば、通常、技術的な記事や読書メモを投稿します。コミュニケーションを歓迎します。

推奨チュートリアル: 「JS チュートリアル

以上がPromise、async、await を理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjianshu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。