ホームページ ウェブフロントエンド jsチュートリアル ES6のasync+await同期・非同期ソリューションの詳細説明

ES6のasync+await同期・非同期ソリューションの詳細説明

Sep 20, 2017 am 09:18 AM
プラン 詳しい説明

この記事では、ES6 の async+await 同期/非同期ソリューションの詳細な説明を主に紹介します。この記事では、async + await のブロックを解除するための最も簡潔な方法を使用します。興味のある方は詳細をご覧ください。

非同期プログラミングは常に JavaScript の主要な問題です。プログラミング。非同期ソリューションに関しては、ES6 でまず状態管理に基づく Promise が登場し、次に Generator 関数 + co 関数、そして ES7 の async + await ソリューションが登場しました。

この記事は、最も簡潔な方法で非同期 + 待機のブロックを解除することを目的としています。

非同期プログラミングのいくつかのシナリオ

よくある質問から始めましょう: for ループで反復シーケンスを非同期に出力するにはどうすればよいですか?

この質問に答えるために、クロージャまたは ES6 で指定されている let ブロックレベルのスコープを使用することは簡単に考えられます。


for (let val of [1, 2, 3, 4]) {
  setTimeout(() => console.log(val),100);
}
// => 预期结果依次为:1, 2, 3, 4
ログイン後にコピー

ここで説明しているのは、均等に発生する非同期イベントであり、あらかじめ決められた順番で非同期キューにキューイングされて実行を待っています。

非同期が均等に発生しない場合、非同期キューに登録される順番が狂います。


for (let val of [1, 2, 3, 4]) {
  setTimeout(() => console.log(val), 100 * Math.random());
}
// => 实际结果是随机的,依次为:4, 2, 3, 1
ログイン後にコピー

返される結果は順序が狂っていて制御不能ですが、これが最も現実的な非同期です。しかし、別の状況として、ループ内で前の非同期実行を完了させ、次の非同期実行を再度実行したい場合はどうすればよいでしょうか?


for (let val of ['a', 'b', 'c', 'd']) {
  // a 执行完后,进入下一个循环
  // 执行 b,依此类推
}
ログイン後にコピー

これは単なる複数の非同期「シリアル」ではありませんか!

非同期操作をコールバックに入れ子にしてコールバックする方法で、この問題は解決されます。あるいは、Promise + then() を使用してレイヤーをネストすることでも、問題を解決できる可能性があります。ただし、このネストメソッドをループで記述することに固執すると、非常に手間がかかると思います。もっと良い方法はないでしょうか?

非同期同期ソリューション

想像してみてください。データのバッチをサーバーに送信したい場合、前のバッチが正常に送信された場合 (つまり、サーバーが成功の応答を返した場合) にのみ、次のデータ バッチを送信できるようになります。送信されない場合、送信は終了します。これは、「for ループ内の相互依存した非同期操作」の典型的な例です。

明らかに、この「シリアル」非同期は実際には同期とみなすことができます。アウトオブオーダーの非同期よりも時間がかかります。論理的に言えば、ブロックを「スキップ」して時間を短縮するために、プログラムを非同期で実行する必要があります。しかし逆に、一連の非同期「シリアル」が必要な場合、どのように適切にプログラムすればよいでしょうか?

この「シリアル」非同期については、ES6 はこの問題を非常に簡単に解決します。


async function task () {
  for (let val of [1, 2, 3, 4]) {
    // await 是要等待响应的
    let result = await send(val);
    if (!result) {
      break;
    }
  }
}
task();
ログイン後にコピー

文字通り、このサイクルです。結果が得られたら、次のサイクルが実行されます。したがって、ループが終了するまで、実行するたびにループが一時停止 (「スタック」) されます。このコーディング実装により、ネストされた「コールバック地獄」の問題が効果的に排除され、認知的困難が軽減されます。

これは、非同期の問題を同期するための解決策です。この解決策に関して、Promise が主に非同期コールバックの問題を解決するのであれば、async + await は主に非同期の問題の同期化と非同期プログラミングの認知的負担の軽減の問題を解決します。

async + await 「外側は違うけど、内側は同じ」

以前この API に触れたとき、面倒なドキュメントを見て、async + await は主に非同期の問題を解決するために使用されるものだと思いましたそして同期。

実際にはそうではありません。上記の例からわかるように、async キーワードは非同期関数を宣言します。この非同期関数の本体には、動作が同期的に実行されることを通知する await ステートメントの行があり、上下の隣接するコードが実行されます。一行ずつ順番に。

この形式的なものをもう一度翻訳すると、次のようになります。

1. async 関数が実行された後、常に Promise オブジェクトが返されます
2. await が配置されているステートメントの行は同期です

このうち、1 は From を説明します。外部では、タスクメソッドは実行後に Promise オブジェクトを返すので、タスクが非同期メソッドであることがわかります。次のように使用されることに疑いの余地はありません。


task().then((val) => {alert(val)})
   .then((val) => {alert(val)})
ログイン後にコピー

2 は、タスク関数内で非同期が同期に「カット」されたことを示しています。全体としては、実行に少し時間がかかる関数にすぎません。

1と2を組み合わせると、形式的には「タスク全体は非同期関数であり、内部部分はすべて同期している」ことを「外見は違うが中身は同じ」といいます。 。

全体は非同期関数であり、理解するのは難しくありません。実装に関して言えば、言語レベルでは、async キーワードが呼び出されるとき、関数の実行の最後に Promise が強制的に追加されます。その応答は次のとおりです。内部は同期しています。実際、await 呼び出しにより、次のステートメント (関数) が再帰的に実行されます。結果が取得され、そのステータスが変更されるまでは解決されません。解決が完了した後でのみ、コードの await 行が完了したとみなされます。次の行まで実行されます。したがって、外側に大きな for ループがありますが、for ループ全体が順番にシリアル化されます。

したがって、上記のフレームワークの外観だけから、async + await の意味を理解するのは難しくありません。使い方はとても簡単ですが、Promise はマスターする必要がある基本的な部分です。

秉承本次《重读 ES6》系列的原则,不过多追求理解细节和具体实现过程。我们继续巩固一下这个 “形式化” 的理解。

async + await 的进一步理解

有这样的一个异步操作 longTimeTask,已经用 Promise 进行了包装。借助该函数进行一系列验证。


const longTimeTask = function (time) {
 return new Promise((resolve, reject) => {
  setTimeout(()=>{
   console.log(`等了 ${time||'xx'} 年,终于回信了`);
   resolve({'msg': 'task done'});
  }, time||1000)
 })
}
ログイン後にコピー

async 函数的执行情况

如果,想查看 async exec1 函数的返回结果,以及 await 命令的执行结果:


const exec1 = async function () {
 let result = await longTimeTask();
 console.log('result after long time ===>', result);
}
// 查看函数内部执行顺序
exec1();
// => 等了 xx 年,终于回信了
// => result after long time ===> Object {msg: "task done"}

//查看函数总体返回值
console.log(exec1());
// => Promise {[[PromiseStatus]]: "pending",...}
// => 同上
ログイン後にコピー

以上 2 步执行,清晰的证明了 exec1 函数体内是同步、逐行逐行执行的,即先执行完异步操作,然后进行 console.log() 打印。而 exec1() 的执行结果就直接是一个 Promise,因为它最先会蹦出来一串 Promise ...,然后才是 exec1 函数的内部执行日志。

因此,所有验证,完全符合 整体是一个异步函数,内部整个是同步的 的总结。

await 如何执行其后语句?

回到 await ,看看它是如何执行其后边的语句的。假设:让 longTimeTask() 后边直接带 then() 回调,分两种情况:

1)then() 中不再返回任何东西
2) then() 中继续手动返回另一个 promise


const exec2 = async function () {
 let result = await longTimeTask().then((res) => {
  console.log('then ===>', res.msg);
  res.msg = `${res.msg} then refrash message`;
  // 注释掉这条 return 或 手动返回一个 promise
  return Promise.resolve(res);
 });
 console.log('result after await ===>', result.msg);
}
exec2();
// => 情况一 TypeError: Cannot read property 'msg' of undefined
// => 情况二 正常
ログイン後にコピー

首先,longTimeTask() 加上再多得 then() 回调,也不过是放在了它的回调列队 queue 里了。也就是说,await 命令之后始终是一条 表达式语句,只不过上述代码书写方式比较让人迷惑。(比较好的实践建议是,将 longTimeTask 方法身后的 then() 移入 longTimeTask 函数体封装起来)

其次,手动返回另一个 promise 和什么也不返回,关系到 longTimeTask() 方法最终 resolve 出去的内容不一样。换句话说,await 命令会提取其后边的promise 的 resolve 结果,进而直接导致 result 的不同。

值得强调的是,await 命令只认 resolve 结果,对 reject 结果报错。不妨用以下的 return 语句替换上述 return 进行验证。


return Promise.reject(res);
ログイン後にコピー

最后

其实,关于异步编程还有很多可以梳理的,比如跨模块的异步编程、异步的单元测试、异步的错误处理以及什么是好的实践。All in all, 限于篇幅,不在此汇总了。最后,async + await 确实是一个很优雅的方案。

以上がES6のasync+await同期・非同期ソリューションの詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

C++のmode関数の詳しい解説 C++のmode関数の詳しい解説 Nov 18, 2023 pm 03:08 PM

C++ のモード関数の詳細な説明 統計において、モードとは、一連のデータ内で最も頻繁に現れる値を指します。 C++ 言語では、モード関数を記述することによって、任意のデータセット内のモードを見つけることができます。モード関数はさまざまな方法で実装できます。一般的に使用される 2 つの方法を以下で詳しく紹介します。 1 つ目の方法は、ハッシュ テーブルを使用して各数値の出現回数をカウントすることです。まず、各数値をキー、出現回数を値とするハッシュ テーブルを定義する必要があります。次に、特定のデータセットに対して次を実行します。

Win11での管理者権限の取得について詳しく解説 Win11での管理者権限の取得について詳しく解説 Mar 08, 2024 pm 03:06 PM

Windows オペレーティング システムは世界で最も人気のあるオペレーティング システムの 1 つであり、その新バージョン Win11 が大きな注目を集めています。 Win11 システムでは、管理者権限の取得は重要な操作であり、管理者権限を取得すると、ユーザーはシステム上でより多くの操作や設定を実行できるようになります。この記事では、Win11システムで管理者権限を取得する方法と、権限を効果的に管理する方法を詳しく紹介します。 Win11 システムでは、管理者権限はローカル管理者とドメイン管理者の 2 種類に分かれています。ローカル管理者はローカル コンピュータに対する完全な管理権限を持っています

Oracle SQLの除算演算の詳細説明 Oracle SQLの除算演算の詳細説明 Mar 10, 2024 am 09:51 AM

OracleSQL の除算演算の詳細な説明 OracleSQL では、除算演算は一般的かつ重要な数学演算であり、2 つの数値を除算した結果を計算するために使用されます。除算はデータベース問合せでよく使用されるため、OracleSQL での除算演算とその使用法を理解することは、データベース開発者にとって重要なスキルの 1 つです。この記事では、OracleSQL の除算演算に関する関連知識を詳細に説明し、読者の参考となる具体的なコード例を示します。 1. OracleSQL での除算演算

C++の剰余関数の詳しい解説 C++の剰余関数の詳しい解説 Nov 18, 2023 pm 02:41 PM

C++ の剰余関数の詳しい説明 C++ では、剰余演算子 (%) を使用して、2 つの数値を除算した余りを計算します。これは、オペランドが任意の整数型 (char、short、int、long など) または浮動小数点数型 (float、double など) になる二項演算子です。剰余演算子は、被除数と同じ符号の結果を返します。たとえば、整数の剰余演算の場合、次のコードを使用して実装できます。

Vue.nextTick関数の使い方と非同期更新での応用について詳しく解説 Vue.nextTick関数の使い方と非同期更新での応用について詳しく解説 Jul 26, 2023 am 08:57 AM

Vue.nextTick 関数の使い方と非同期更新での応用について詳しく説明 Vue の開発では、DOM を変更した直後にデータを更新したり、関連する操作が必要になったりするなど、データを非同期で更新する必要がある状況によく遭遇します。データが更新された直後に実行されます。このような問題を解決するために登場したのが、Vue が提供する .nextTick 関数です。この記事では、Vue.nextTick 関数の使用法を詳しく紹介し、コード例と組み合わせて、非同期更新でのアプリケーションを説明します。 1.Vue.nex

php-fpmのチューニング方法を詳しく解説 php-fpmのチューニング方法を詳しく解説 Jul 08, 2023 pm 04:31 PM

PHP-FPM は、PHP のパフォーマンスと安定性を向上させるために一般的に使用される PHP プロセス マネージャーです。ただし、高負荷環境では、PHP-FPM のデフォルト設定ではニーズを満たせない場合があるため、チューニングが必要です。この記事では、PHP-FPM のチューニング方法を詳しく紹介し、いくつかのコード例を示します。 1. プロセスの数を増やす デフォルトでは、PHP-FPM はリクエストを処理するために少数のプロセスのみを開始します。高負荷環境では、プロセス数を増やすことで PHP-FPM の同時実行性を高めることができます。

PHPモジュロ演算子の役割と使い方を詳しく解説 PHPモジュロ演算子の役割と使い方を詳しく解説 Mar 19, 2024 pm 04:33 PM

PHP のモジュロ演算子 (%) は、2 つの数値を除算した余りを取得するために使用されます。この記事では、モジュロ演算子の役割と使用法について詳しく説明し、読者の理解を深めるために具体的なコード例を示します。 1. モジュロ演算子の役割 数学では、整数を別の整数で割ると、商と余りが得られます。たとえば、10 を 3 で割ると、商は 3 になり、余りは 1 になります。モジュロ演算子は、この剰余を取得するために使用されます。 2. モジュロ演算子の使用法 PHP では、% 記号を使用してモジュロを表します。

Linuxシステムコールsystem()関数の詳細説明 Linuxシステムコールsystem()関数の詳細説明 Feb 22, 2024 pm 08:21 PM

Linux システム コール system() 関数の詳細説明 システム コールは、Linux オペレーティング システムの非常に重要な部分であり、システム カーネルと対話する方法を提供します。その中でも、system()関数はよく使われるシステムコール関数の一つです。この記事では、system() 関数の使用法を詳しく紹介し、対応するコード例を示します。システム コールの基本概念 システム コールは、ユーザー プログラムがオペレーティング システム カーネルと対話する方法です。ユーザープログラムはシステムコール関数を呼び出してオペレーティングシステムを要求します。

See all articles