ネットユーザーの質問に答えます: Promise オブジェクトを Await すると何が起こりますか?

ネットユーザーの質問に答えます: Promise オブジェクトを Await すると何が起こりますか?

みなさんこんにちは。私は次男です。

最初の2つの記事が公開された後、何人かのネットユーザーが裏で私にいくつかの質問をしたので、それらをまとめて要約しました。この記事はネットユーザーの質問への回答であると同時に、前の2つの記事の補足とレビューでもあります。

最初の 2 つの記事へのリンクは次のとおりです。

Node.js のコアイベントループのグラフィカルな説明

​​マルチグラフ分析式 async=Promise+Generator+Automatic Executor​​

図1: 非同期関数のコード例

質問 0 : 前の記事で説明したジェネレーターと自動実行プログラムは、異なるスレッドで実行されますか?

回答 0 : ジェネレーターとエグゼキューターは両方とも、JS コードを実行するメイン スレッドであるイベント ループ スレッドで実行されます。もう一度強調しておきますが、これらは 2 つのスレッドで実行されているわけではありません。

Node.js公式サイトのevent-loopの説明をもう一度見てみましょう。重要な点を強調します。JS コードはシングルスレッド方式で実行されます。

 イベントループにより JavaScript はシングル スレッドであるにもかかわらず 可能限り操作システムカーネルオフロードすること Node.js ブロッキングI / O 操作実行できるようなります

質問 1 : ステートメント await p は非同期要求を生成しますか?

回答 1 : いいえ、そうではありません。 await は、p の状態が保留から解決に変化するか、保留から拒否に変化するかを待機するだけです。

質問 2 : 非同期リクエストはいつ生成されますか?

回答 2 : setTimeout が実行されると Promise executor で生成されます。

​次のテキストでは、new Promise() を呼び出すときに渡されるコールバック (resolve, reject)=>{ /* your code */ は、executor と呼ばれます。パラメータresolveとrejectはPromise自体によって実装されます。このエグゼキュータは、new Promise() が呼び出されるとすぐに実行されることに注意してください。

executor で fs.read(fd[, options], callback) のようなステートメントを実行すると、同様に、fs.read() が呼び出されたときに非同期リクエストが生成されます。​

質問3 :pの状態が変化した後、resolve(200)を通過した200が変数resの評価結果になるのはなぜですか?

回答 3 : これが、await の背後にある実装原則を理解する必要がある理由です。図 2 と 4 を参考にしてこれを確認してみましょう。

図 2 に示すように、まず async 関数がジェネレーター関数に変換されます。ただし、ジェネレーター関数はそれ自体では自動的に実行できないため、自動実行プログラムと組み合わせて実行する必要があります。オートマトンとは愛情深い母親のようなもので、ジェネレーターとは純真な幼児のようなものだ。子どもは一定の距離を歩くたびに立ち止まり、後ろからついてくる母親を振り返り、母親から励ましやご褒美をもらって次の目標へと進んでいきます。

図2: 非同期関数をジェネレータ関数に変換する例

図 4 を説明する前に、yield 式と yield ステートメントという 2 つの重要な概念を確認する必要があります。図3に示すように:

  • a+b は式であり、その評価結果は { value: xxx, done: xxx } の value プロパティに影響します。また、 { value: xxx, done: xxx } は、呼び出し元がイテレータを介して next() メソッドを呼び出したときの戻り値です。
  • yield a+b は yield ステートメントです。呼び出し元は、実際のパラメータを next() メソッドに渡すことで、yield ステートメントの戻り値に影響を与えることができます。たとえば、next(200) は変数 a1 を 200 にします。

図 3 には、ジェネレーター関数の実行の一時停止ポイント、つまり yield 式が評価された後、yield ステートメントが返される前という重要なポイントも示されています。

図3: 収量式と収量ステートメントの比較

質問 3 にもっとわかりやすく答えるために、次兄が図 4 を描いてくれました。

このステップでは、エグゼキュータを介してジェネレータの呼び出しを開始します。

② ここで実際のジェネレータの呼び出しが発生しますが、ジェネレータ関数はステップ ② では何も行わず、すぐにイテレータを返します。

③ここから自動アクチュエータは駆動ジェネレータモードに入ります。 ③ このステップでは、g.next() が初めて実行されるときに値を挿入できないため、パラメータデータに値を割り当てません。

④ このステップで g.next() が呼び出されるたびに、ジェネレーターは yield で最後に一時停止した位置から実行を開始し、再び yield に遭遇するまで実行されます。

⑤ したがって、g.next() の最初の呼び出しにより、左のジェネレーター関数は関数の先頭から yield に遭遇するまで実行されます。

⑤でマークされたコード実行プロセスでは、実際に Promise オブジェクトが作成され、Promise executor に 1 秒のタイマーが設定されていることがわかります。このエグゼキュータは Promise オブジェクトが作成されると同時に実行されますが、⑦のコードは 1 秒後まで実行されないことに注意してください。

⑥ジェネレータ関数が一時停止する前に、yield式の評価結果が{value:xxx, done:xxx}を通じてg.next()の呼び出し元に返されます。これは右図の④の位置です。

したがって、右の図の位置 ④ にある変数 result は { value: p, done: false} であると推測できるはずです。ここでpは⑤の実行中に生成されたPromiseオブジェクトです。

このようにして、Promise オブジェクトはジェネレーター関数と自動エグゼキューターの間を流れます。それはとても独創的なプロセスです。

そうすれば、右側のステートメント result.value.then(callback) を見ても混乱することはありません。これは Promise の標準的な使用法です。 p の状態が解決されると、当然 ⑧ のコールバックが実行される機会が得られます。

⑦ 1秒があっという間に経過し、resolve(200)が実行できるようになります。これを実行するとpの状態が解決されるため、⑧で辛抱強く待機していたコールバックが動作を開始します。

⑧ はい、この時点でデータの値は200です。 Promise の使用に慣れている場合、これは非常に自然なことです。

⑨ 自動実行プログラムは next(data)​ を再度実行します。しかし今回は実際のパラメータ200が渡されます。そのため、今回は④で実行されるコードは g.next(200) になります。

⑩自動実行プログラムはg.next(200)を実行し、必然的にジェネレータ関数を開始して前進を続けます。

前回ジェネレータ関数がどこで停止したかを覚えていますか?はい、左側の⑤の矢印の位置です。ジェネレータ関数が再開したときに最初に行うことは、yield ステートメントを評価することです。

g.next()​ のように駆動すると、yield ステートメントは undefined を返します。しかし今回は g.next(200) を実行する点が異なります。非常に巧妙なことに、 next() に渡された引数 200 は、 yield ステートメントの戻り値として左変数 res​ に割り当てられます

図4: ジェネレーター + オートメーターの詳細

図 1 のサンプル コードをもう一度見て、要約してみましょう。

  1. await p ステートメントは、yield p ステートメント + 自動実行プログラムをラップする糖衣です。
  2. いわゆる await p pause は、メイン スレッドが JS コードの実行を一時停止することを意味するものではありません。逆に、メインスレッドは他の JS コードの実行を継続します。
  3. await は p の状態が変化するのを待機します。この待ち時間はどれくらいですか?すべては、p が作成されたときに、executor で resolve() または reject() がいつ呼び出されるかによって決まります。
  4. await p ステートメントを実行すると、p の状態が変化したかどうかに関係なく、await p を実行すると、代わりに V8 エンジンが自動エグゼキュータで実行されます。これは yield p ステートメントによるものです。
  5. 自動実行者は、どこにでもあなたについていく母親のようなものです。 p を取得した後、状態が変化した後の p の値を取得するまで辛抱強く待機します。最後に、g.next(value) を通じて、愛用のジェネレーター関数に値を返します。

図5: 図1と同じ

<<:  VMware は、ワークロードのパフォーマンスを向上させ、企業の TCO を削減する新しいコンピューティングおよびストレージ ソリューションをリリースしました。

>>:  Prometheus、Istio、Hpa、Keda、Karpenter をベースにした K8s アプリケーションとノードの弾力性の実装

推薦する

TudouとYoukuの合併後、「1234」ビデオウェブサイトのパターンが徐々に形作られる

市場観察【上海8月21日新華社】中国の二大動画サイト、優酷(Youku)と土豆(Tudou)の合併案...

龔海燕の2番目の起業ベンチャーの分析:ウェディングドレスの電子商取引の見通しは信頼できるか?

【紹介】Gong Haiyan は出会い系サイトの立ち上げと管理に 10 年の経験を持っています。ウ...

hostodo-$6/5IP/2g メモリ/75g ハードディスク/2T トラフィック/IPv6 をサポート/無制限の VPS 作成

hostodo のボスは数日間チケットを無視していたか、返信が非常に遅かったようです。多くの人が不満...

カザフスタン VPS: onehost、月額 8.85 ドル、AMD EPYC+NVMe+1Gbps 帯域幅、無制限のトラフィック

onehost.kz は 2009 年に設立され、RIPE NCC のメンバーであるカザフスタンのホ...

実は、あなたは知らないうちに偽のSEOを行っているのです

誰もがこう感じているかもしれません。「なぜ私たちはポスト SEO 時代にまだ準 SEO 時代のことを...

ウェブサイトのナビゲーション構造を最適化し、降格方法を復元する方法

ショートビデオ、セルフメディア、インフルエンサーのためのワンストップサービスウェブサイトの SEO ...

雲の中での戦い: 巨人たちは大成功を収めて勢いづいているが、追っ手たちは何も残されていない?

2018 年の初めには、雲が駆け巡り、何千頭もの馬が疾走します。大成功を収めて絶好調の人もいれば、た...

Kubernetes (K8S) 管理、グラフィカル インターフェース、Web UI

1. k8s管理インターフェース主なものを3つ挙げます。公式 kubernetes-dashboar...

unesty: ドイツ VPS 春のセール、月額 3.75 ユーロ、9G メモリ/4 コア (AMD)/75g NVMe/10G 帯域幅/無制限トラフィック

ドイツのクラウド サーバー マーチャント unesty が春のプロモーションを実施しています。ドイツ...

パンデミックの間、クラウドデスクトップにより、対面会議を伴わない政府業務を機密に保ち、スケジュールすることが可能になった。

「クラウドデスクトップを通じて、これまでは機密保持の要件によりインターネット上では知ることのできなか...

ウェブサイトを最適化する過程で、SEO担当者は徐々に独自の最適化思考システムを確立する必要がある。

ご存知のとおり、ウェブサイトの運用とメンテナンスの最適化は体系的なプロセスです。業界やウェブサイトの...

ソフト記事を再投稿する際に他の人がリンクを削除しないようにする方法

概要: この記事では主に、Webmaster Home や A5 Webmaster Network...

Qingfeng アルゴリズムによるタイトルの不正行為で企業サイトが最近大規模な処罰を受けた件から、何を学びましたか?

2018年最もホットなプロジェクト:テレマーケティングロボットがあなたの参加を待っています7月28日...

BlueVM レビュー: 4GB メモリ/100GB ハードドライブ/3TB トラフィック/月額 3.3 ドル

以前、この VPS について記事を公開しました: bluevm - 4g メモリ/100g ハードド...

ウェブサイトを構築するにはどれくらいの費用がかかりますか?

2018年最もホットなプロジェクト:テレマーケティングロボットがあなたの参加を待っていますウェブサイ...