検索
ホームページウェブフロントエンドjsチュートリアルES6 非同期 + 待機同期/非同期ソリューション

この記事では、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 确实是一个很优雅的方案。

相关推荐:

让Express支持async方法分享

NodeJs通过async和await处理异步的方法

Node.js中如何使用async函数

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

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
CおよびJavaScript:接続が説明しましたCおよびJavaScript:接続が説明しましたApr 23, 2025 am 12:07 AM

CおよびJavaScriptは、WebAssemblyを介して相互運用性を実現します。 1)CコードはWebAssemblyモジュールにコンパイルされ、JavaScript環境に導入され、コンピューティングパワーが強化されます。 2)ゲーム開発では、Cは物理エンジンとグラフィックスレンダリングを処理し、JavaScriptはゲームロジックとユーザーインターフェイスを担当します。

Webサイトからアプリまで:JavaScriptの多様なアプリケーションWebサイトからアプリまで:JavaScriptの多様なアプリケーションApr 22, 2025 am 12:02 AM

JavaScriptは、Webサイト、モバイルアプリケーション、デスクトップアプリケーション、サーバー側のプログラミングで広く使用されています。 1)Webサイト開発では、JavaScriptはHTMLおよびCSSと一緒にDOMを運用して、JQueryやReactなどのフレームワークをサポートします。 2)ReactNativeおよびIonicを通じて、JavaScriptはクロスプラットフォームモバイルアプリケーションを開発するために使用されます。 3)電子フレームワークにより、JavaScriptはデスクトップアプリケーションを構築できます。 4)node.jsを使用すると、JavaScriptがサーバー側で実行され、高い並行リクエストをサポートします。

Python vs. JavaScript:ユースケースとアプリケーションと比較されますPython vs. JavaScript:ユースケースとアプリケーションと比較されますApr 21, 2025 am 12:01 AM

Pythonはデータサイエンスと自動化により適していますが、JavaScriptはフロントエンドとフルスタックの開発により適しています。 1. Pythonは、データ処理とモデリングのためにNumpyやPandasなどのライブラリを使用して、データサイエンスと機械学習でうまく機能します。 2。Pythonは、自動化とスクリプトにおいて簡潔で効率的です。 3. JavaScriptはフロントエンド開発に不可欠であり、動的なWebページと単一ページアプリケーションの構築に使用されます。 4. JavaScriptは、node.jsを通じてバックエンド開発において役割を果たし、フルスタック開発をサポートします。

JavaScript通訳者とコンパイラにおけるC/Cの役割JavaScript通訳者とコンパイラにおけるC/Cの役割Apr 20, 2025 am 12:01 AM

CとCは、主に通訳者とJITコンパイラを実装するために使用されるJavaScriptエンジンで重要な役割を果たします。 1)cは、JavaScriptソースコードを解析し、抽象的な構文ツリーを生成するために使用されます。 2)Cは、Bytecodeの生成と実行を担当します。 3)Cは、JITコンパイラを実装し、実行時にホットスポットコードを最適化およびコンパイルし、JavaScriptの実行効率を大幅に改善します。

JavaScript in Action:実際の例とプロジェクトJavaScript in Action:実際の例とプロジェクトApr 19, 2025 am 12:13 AM

現実世界でのJavaScriptのアプリケーションには、フロントエンドとバックエンドの開発が含まれます。 1)DOM操作とイベント処理を含むTODOリストアプリケーションを構築して、フロントエンドアプリケーションを表示します。 2)node.jsを介してRestfulapiを構築し、バックエンドアプリケーションをデモンストレーションします。

JavaScriptとWeb:コア機能とユースケースJavaScriptとWeb:コア機能とユースケースApr 18, 2025 am 12:19 AM

Web開発におけるJavaScriptの主な用途には、クライアントの相互作用、フォーム検証、非同期通信が含まれます。 1)DOM操作による動的なコンテンツの更新とユーザーインタラクション。 2)ユーザーエクスペリエンスを改善するためにデータを提出する前に、クライアントの検証が実行されます。 3)サーバーとのリフレッシュレス通信は、AJAXテクノロジーを通じて達成されます。

JavaScriptエンジンの理解:実装の詳細JavaScriptエンジンの理解:実装の詳細Apr 17, 2025 am 12:05 AM

JavaScriptエンジンが内部的にどのように機能するかを理解することは、開発者にとってより効率的なコードの作成とパフォーマンスのボトルネックと最適化戦略の理解に役立つためです。 1)エンジンのワークフローには、3つの段階が含まれます。解析、コンパイル、実行。 2)実行プロセス中、エンジンはインラインキャッシュや非表示クラスなどの動的最適化を実行します。 3)ベストプラクティスには、グローバル変数の避け、ループの最適化、constとletsの使用、閉鎖の過度の使用の回避が含まれます。

Python vs. JavaScript:学習曲線と使いやすさPython vs. JavaScript:学習曲線と使いやすさApr 16, 2025 am 12:12 AM

Pythonは、スムーズな学習曲線と簡潔な構文を備えた初心者により適しています。 JavaScriptは、急な学習曲線と柔軟な構文を備えたフロントエンド開発に適しています。 1。Python構文は直感的で、データサイエンスやバックエンド開発に適しています。 2。JavaScriptは柔軟で、フロントエンドおよびサーバー側のプログラミングで広く使用されています。

See all articles

ホット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衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

SublimeText3 Linux 新バージョン

SublimeText3 Linux 新バージョン

SublimeText3 Linux 最新バージョン

VSCode Windows 64 ビットのダウンロード

VSCode Windows 64 ビットのダウンロード

Microsoft によって発売された無料で強力な IDE エディター

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

このプロジェクトは osdn.net/projects/mingw に移行中です。引き続きそこでフォローしていただけます。 MinGW: GNU Compiler Collection (GCC) のネイティブ Windows ポートであり、ネイティブ Windows アプリケーションを構築するための自由に配布可能なインポート ライブラリとヘッダー ファイルであり、C99 機能をサポートする MSVC ランタイムの拡張機能が含まれています。すべての MinGW ソフトウェアは 64 ビット Windows プラットフォームで実行できます。

Dreamweaver Mac版

Dreamweaver Mac版

ビジュアル Web 開発ツール

DVWA

DVWA

Damn Vulnerable Web App (DVWA) は、非常に脆弱な PHP/MySQL Web アプリケーションです。その主な目的は、セキュリティ専門家が法的環境でスキルとツールをテストするのに役立ち、Web 開発者が Web アプリケーションを保護するプロセスをより深く理解できるようにし、教師/生徒が教室環境で Web アプリケーションを教え/学習できるようにすることです。安全。 DVWA の目標は、シンプルでわかりやすいインターフェイスを通じて、さまざまな難易度で最も一般的な Web 脆弱性のいくつかを実践することです。このソフトウェアは、