ホームページ > 記事 > ウェブフロントエンド > Promise、async、await を理解する
前の記事では主に、同期と非同期、「実行スタック」、「メッセージ キュー」、そしてそれぞれから派生した「マクロ タスク」と「マイクロ タスク」について説明しました。それについてはあまり詳しくありませんが、次のリンクにアクセスしてください:
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 サイトの他の関連記事を参照してください。