なぜ?
JavaScript Promise が内部でどのようにコールバックを非同期的に実行するかを理解するため。
JavaScript で独自の Promise を作成しましょう! Promise/A 仕様に従います。これは、Promise が非同期操作を処理し、解決、拒否し、予測可能なチェーンとエラー処理を保証する方法を概説しています。
話を簡単にするために、Promises/A 仕様の ✅ でマークされている主要なルールに焦点を当てます。これは完全な実装ではなく、簡略化されたバージョンになります。構築するものは次のとおりです:
1. 用語
1.1 'promise' は、動作がこの仕様に準拠する then メソッドを持つオブジェクトまたは関数です。
1.2 thenable' は、then メソッドを定義するオブジェクトまたは関数です。
1.3 「値」は、任意の有効な JavaScript 値 (未定義、thenable、または Promise を含む) です。
1.4 「例外」は、throw ステートメントを使用してスローされる値です。
1.5 'reason' は、Promise が拒否された理由を示す値です。
2. 要件
2.1 プロミスの状態
Promise は、保留中、履行済み、拒否の 3 つの状態のいずれかである必要があります。
2.1.1.保留中の場合、約束: ✅
⟶は、満たされた状態または拒否された状態のいずれかに移行する可能性があります。
2.1.2.果たされたときの約束: ✅
⟶は他の状態に遷移してはなりません。
⟶には値が必要であり、変更することはできません。
2.1.3.拒否された場合の約束: ✅
⟶は他の状態に遷移してはなりません。
⟶には理由があり、それを変えてはなりません。
2.2 当時の方法
Promise は、その現在または最終的な値または理由にアクセスするための then メソッドを提供する必要があります。
Promise の then メソッドは 2 つの引数を受け入れます:
promise.then(onFulfilled, onRejected);
2.2.1. onFulfilled と onRejected は両方ともオプションの引数です: ✅
⟶ onFulfilled が関数ではない場合、無視する必要があります。
⟶ onRejected が関数ではない場合、無視する必要があります。
2.2.2. onFulfilled が関数の場合: ✅
⟶ 最初の引数として Promise の値を指定して、Promise が実行された後に呼び出さなければなりません。
⟶ 約束が果たされる前に呼び出してはなりません。
⟶ 複数回呼び出すことはできません。
2.2.3. onRejected が関数の場合、✅
⟶ Promise が拒否された後に、Promise の理由を最初の引数として呼び出す必要があります。
⟶ Promise が拒否される前に呼び出してはなりません。
⟶ 複数回呼び出すことはできません。
2.2.4. onFulfilled または onRejected は、実行コンテキスト スタックにプラットフォーム コードのみが含まれるまで呼び出さないでください。 ✅
2.2.5. onFulfilled と onRejected は関数として呼び出す必要があります (つまり、this 値なし)。 ✅
2.2.6. then は同じ Promise で複数回呼び出される可能性があります。 ✅
⟶ Promise が履行された場合、それぞれの onFulfilled コールバックはすべて、then への呼び出しの順序で実行する必要があります。
⟶ Promise が拒否された場合、すべての onRejected コールバックは、最初の then 呼び出しの順序で実行する必要があります。
2.2.7.その後、Promise を返さなければなりません。 ✅
promise.then(onFulfilled, onRejected);
⟶ onFulfilled または onRejected のいずれかが値 x を返した場合、Promise 解決プロシージャ [[Resolve]](promise2, x) を実行します。 ❌
⟶ onFulfilled または onRejected のいずれかが例外 e をスローした場合、promise2 は e を理由として拒否されなければなりません。 ❌
⟶ onFulfilled が関数ではなく、promise1 が履行される場合、promise2 はpromise1 と同じ値で履行されなければなりません。 ❌
⟶ onRejected が関数ではなく、promise1 が拒否された場合、promise2 は、promise1 と同じ理由で拒否されなければなりません。 ❌
実装
JavaScript Promise は引数として実行関数を受け取り、Promise が作成されるとすぐに呼び出されます。
promise2 = promise1.then(onFulfilled, onRejected);
new Promise(excecutor);
コアとなる Promises/A 仕様では、Promise を作成、履行、または拒否する方法については扱っていません。それはあなた次第です。ただし、Promise の構築のために提供する実装は、JavaScript の非同期 API と互換性がある必要があります。これが Promise クラスの最初のドラフトです:
const promise = new Promise((resolve, reject) => { // Runs some async or sync tasks });
ルール 2.1 (約束の状態) では、約束は保留、履行、または拒否の 3 つの状態のいずれかでなければならないと規定されています。また、これらの各状態で何が起こるかについても説明します。
Promise は、履行または拒否された場合、他の状態に移行してはなりません。したがって、移行を行う前に、Promise が保留状態であることを確認する必要があります。
class YourPromise { constructor(executor) { this.state = 'pending'; this.value = undefined; this.reason = undefined; const resolve = value => { if (this.state === 'pending') { this.state = 'fulfilled'; this.value = value; } }; const reject = reason => { if (this.state === 'pending') { this.state = 'rejected'; this.reason = reason; } }; try { executor(resolve, reject); // The executor function being called immediately } catch (error) { reject(error); } } }
Promise の初期状態が保留中であることはすでにわかっており、明示的に履行または拒否されるまで保留中のままであることを保証します。
const resolve = value => { if (this.state === 'pending') { this.state = 'fulfilled'; this.value = value; } }; const reject = reason => { if (this.state === 'pending') { this.state = 'rejected'; this.reason = reason; } };
Executor 関数は Promise のインスタンス化直後に呼び出されるため、コンストラクター メソッド内で呼び出します。
this.state = 'pending';
YourPromise クラスの最初のドラフトはここで完了します。
Promise/A 仕様は主に、相互運用可能な then() メソッドの定義に焦点を当てています。このメソッドを使用すると、Promise の現在または最終的な値または理由にアクセスできます。それでは、詳しく見ていきましょう。
ルール 2.2 (then メソッド) では、Promise には 2 つの引数を受け入れる then() メソッドが必要であると規定されています。
try { executor(resolve, reject); } catch (error) { reject(error); }
onFulfilled と onRejected は両方とも、promise が履行されるか拒否された後に呼び出す必要があります。関数の場合は、promise の値または理由を最初の引数として渡します。
class YourPromise { constructor(executor) { // Implementation } then(onFulfilled, onRejected) { // Implementation } }
さらに、Promise が履行または拒否される前に呼び出してはならず、複数回呼び出してはなりません。 onFulfilled と onRejected は両方ともオプションであり、関数でない場合は無視する必要があります。
ルール 2.2、2.2.6、および 2.2.7 を見ると、Promise には then() メソッドが必要であり、then() メソッドは複数回呼び出すことができ、メソッドは約束:
promise.then(onFulfilled, onRejected);
物事を簡単にするために、個別のクラスや関数は扱いません。 executor 関数を渡して、Promise オブジェクトを返します:
promise2 = promise1.then(onFulfilled, onRejected);
executor 関数内で、Promise が履行された場合、onFulfilled コールバックを呼び出し、Promise の値で解決します。同様に、Promise が拒否された場合は、onRejected コールバックを呼び出し、Promise の理由を指定して拒否します。
次の質問は、Promise がまだ保留状態にある場合に、onFulfilled コールバックと onRejected コールバックをどうするかということです。次のように、後で呼び出されるようにそれらをキューに入れます。
new Promise(excecutor);
これで完了です。これは、then() メソッドを含む Promise クラスの 2 番目のドラフトです:
const promise = new Promise((resolve, reject) => { // Runs some async or sync tasks });
ここでは、コールバックを保持するキューとして、onFulfilledCallbacks と onRejectedCallbacks という 2 つのフィールドを導入します。これらのキューには、Promise の保留中に then() 呼び出しを介してコールバックが設定され、Promise が履行または拒否されたときに呼び出されます。
Promise クラスをテストしてみましょう:
class YourPromise { constructor(executor) { this.state = 'pending'; this.value = undefined; this.reason = undefined; const resolve = value => { if (this.state === 'pending') { this.state = 'fulfilled'; this.value = value; } }; const reject = reason => { if (this.state === 'pending') { this.state = 'rejected'; this.reason = reason; } }; try { executor(resolve, reject); // The executor function being called immediately } catch (error) { reject(error); } } }
次のように出力されるはずです:
const resolve = value => { if (this.state === 'pending') { this.state = 'fulfilled'; this.value = value; } }; const reject = reason => { if (this.state === 'pending') { this.state = 'rejected'; this.reason = reason; } };
一方、次のテストを実行すると:
this.state = 'pending';
次の結果が得られます:
try { executor(resolve, reject); } catch (error) { reject(error); }
代わりに:
class YourPromise { constructor(executor) { // Implementation } then(onFulfilled, onRejected) { // Implementation } }
なぜですか?問題は、then() が呼び出された時点で YourPromise インスタンスがすでに解決または拒否されている場合に、then() メソッドがコールバックを処理する方法にあります。具体的には、Promise 状態が保留中でない場合、then() メソッドはコールバックの実行を次のマイクロタスク キューに適切に延期しません。そしてそれが同期実行を引き起こします。テスト例では:
⟶ Promise は、「即時解決」という値で即時に解決されます。
⟶ Promise.then() が呼び出されたとき、状態はすでに満たされているため、onFulfilled コールバックは次のマイクロタスク キューに延期されることなく直接実行されます。
ここで、ルール 2.2.4 が適用されます。このルールにより、Promise がすでに解決または拒否されている場合でも、then() コールバック (onFulfilled または onRejected) が非同期で実行されることが保証されます。これは、現在の実行スタックが完全にクリアされ、プラットフォーム コード (イベント ループやマイクロタスク キューなど) のみが実行されるまで、コールバックを実行してはいけないことを意味します。
このルールがなぜ重要なのでしょうか?
このルールは、Promise/A 仕様の中で最も重要なルールの 1 つです。それは次のことを保証するためです:
⟶ Promise がすぐに解決されたとしても、その then() コールバックはイベント ループの次のティックまで実行されません。
⟶ この動作は、setTimeout や process.nextTick などの JavaScript の他の非同期 API の動作と一致しています。
どうすればこれを達成できるでしょうか?
これは、setTimeout や setImmediate などのマクロタスク メカニズム、または queueMicrotask や process.nextTick などのマイクロタスク メカニズムを使用して実現できます。マイクロタスク、マクロタスク、または同様のメカニズムのコールバックは、現在の JavaScript 実行コンテキストが終了した後に実行されるためです。
上記の問題を解決するには、状態がすでに満たされているか拒否されている場合でも、対応するコールバック (onFulfilled または onRejected) が queueMicrotask を使用して非同期に実行されるようにする必要があります。修正された実装は次のとおりです:
promise.then(onFulfilled, onRejected);
前のサンプル テスト コードを再度実行します。次の出力が得られるはずです:
promise2 = promise1.then(onFulfilled, onRejected);
以上です。
ここまでで、then() からのコールバックがどのように延期され、次のマイクロタスク キューで実行され、非同期動作が可能になるかについて明確に理解できたはずです。 JavaScript で効果的な非同期コードを作成するには、この概念をしっかりと理解することが不可欠です。
次は何ですか?この記事では Promises/A の仕様全体をカバーしていないため、残りの部分を実装して理解を深めてください。
ここまで読んでいただいたので、楽しんで読んでいただければ幸いです。記事をシェアしてください。
フォローしてください:
LinkedIn、Medium、Github
以上がJavaScript で独自の Promise を作成するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

PythonとJavaScriptのパフォーマンスと効率の違いは、主に以下に反映されています。1)解釈された言語として、Pythonはゆっくりと実行されますが、開発効率が高く、迅速なプロトタイプ開発に適しています。 2)JavaScriptはブラウザ内の単一のスレッドに限定されていますが、マルチスレッドおよび非同期I/Oを使用してnode.jsのパフォーマンスを改善でき、両方とも実際のプロジェクトで利点があります。

JavaScriptは1995年に発信され、Brandon Ikeによって作成され、言語をCに実現しました。 2。JavaScriptのメモリ管理とパフォーマンスの最適化は、C言語に依存しています。 3. C言語のクロスプラットフォーム機能は、さまざまなオペレーティングシステムでJavaScriptを効率的に実行するのに役立ちます。

JavaScriptはブラウザとnode.js環境で実行され、JavaScriptエンジンに依存してコードを解析および実行します。 1)解析段階で抽象的構文ツリー(AST)を生成します。 2)ASTをコンパイル段階のバイトコードまたはマシンコードに変換します。 3)実行段階でコンパイルされたコードを実行します。

PythonとJavaScriptの将来の傾向には、1。Pythonが科学コンピューティングの分野での位置を統合し、AI、2。JavaScriptはWebテクノロジーの開発を促進します。どちらもそれぞれのフィールドでアプリケーションシナリオを拡大し続け、パフォーマンスをより多くのブレークスルーを行います。

開発環境におけるPythonとJavaScriptの両方の選択が重要です。 1)Pythonの開発環境には、Pycharm、Jupyternotebook、Anacondaが含まれます。これらは、データサイエンスと迅速なプロトタイピングに適しています。 2)JavaScriptの開発環境には、フロントエンドおよびバックエンド開発に適したnode.js、vscode、およびwebpackが含まれます。プロジェクトのニーズに応じて適切なツールを選択すると、開発効率とプロジェクトの成功率が向上する可能性があります。

はい、JavaScriptのエンジンコアはCで記述されています。1)C言語は、JavaScriptエンジンの開発に適した効率的なパフォーマンスと基礎となる制御を提供します。 2)V8エンジンを例にとると、そのコアはCで記述され、Cの効率とオブジェクト指向の特性を組み合わせて書かれています。3)JavaScriptエンジンの作業原理には、解析、コンパイル、実行が含まれ、C言語はこれらのプロセスで重要な役割を果たします。

JavaScriptは、Webページのインタラクティブ性とダイナミズムを向上させるため、現代のWebサイトの中心にあります。 1)ページを更新せずにコンテンツを変更できます。2)Domapiを介してWebページを操作する、3)アニメーションやドラッグアンドドロップなどの複雑なインタラクティブ効果、4)ユーザーエクスペリエンスを改善するためのパフォーマンスとベストプラクティスを最適化します。

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


ホットAIツール

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

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

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

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

人気の記事

ホットツール

SAP NetWeaver Server Adapter for Eclipse
Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

AtomエディタMac版ダウンロード
最も人気のあるオープンソースエディター

ZendStudio 13.5.1 Mac
強力な PHP 統合開発環境

mPDF
mPDF は、UTF-8 でエンコードされた HTML から PDF ファイルを生成できる PHP ライブラリです。オリジナルの作者である Ian Back は、Web サイトから「オンザフライ」で PDF ファイルを出力し、さまざまな言語を処理するために mPDF を作成しました。 HTML2FPDF などのオリジナルのスクリプトよりも遅く、Unicode フォントを使用すると生成されるファイルが大きくなりますが、CSS スタイルなどをサポートし、多くの機能強化が施されています。 RTL (アラビア語とヘブライ語) や CJK (中国語、日本語、韓国語) を含むほぼすべての言語をサポートします。ネストされたブロックレベル要素 (P、DIV など) をサポートします。

ホットトピック









