序文この記事を書いた理由は、ユニット テストを書くときに、次のテストを実行したからです。 新しい Promise((resolve, deny) => deny(1)).then().catch(err => { コンソール.log(エラー) }) 非同期関数jestTest(){ Promise.resolve().then() を待つ console.log('この時点で、catch が呼び出され、ログが出力されていると予想されます') } jestテスト() イベント ループで catch が呼び出されるまで await を使用してテスト コードをブロックすることはできません。これにより、catch の実行が検出され、テストが合格します。 「魔法」という言葉が使われているのは、promsie のチェーン呼び出しには確かに多くのデフォルト ハンドラーと暗黙的な値の転送があるためです。 プロミスチェーン時間を無駄にしないために、例を見てみましょう。 Promise.resolve('promise1') .then(res => { console.log('promise1-1 then') }) .then(res => { console.log('promise1-2 then') }) .then(res => { console.log('promise1-3 then') }) .then(res => { console.log('promise1-4 then') }) Promise.resolve('promise2') .then(res => { console.log('promise2-1 then') 新しいエラーをスローします('モックエラー1') }) .then(res => { console.log('promise2-2 then') 新しいエラーをスローします('モックエラー2') }) .catch(エラー => { コンソール.log(エラー) }) 上記のコード出力シーケンスに対する回答が次のものと同じ場合は、この記事をスキップできます。
まず前提として、これら 2 つのプロミスの then 呼び出しが交差して積み重ねられていることが既にわかっている必要があります (出力の最初の 3 行からわかるように)。この部分についてよくわからない場合は、イベント ループに関する関連記事を参照してください。同時に、記事で指定されているバージョンでは、Chrome と Nodejs のイベント ループ メカニズムはすでに同じであることに注意してください。 MDN エラーcatch の元の(私が変更した)MDN の説明を見てみましょう。 基本的に、例外が発生すると Promise チェーンは停止し、代わりにチェーン内で catch ハンドラーを探します。 例外が発生するとチェーン呼び出しは停止し、チェーン内で catch ステートメントが見つかり、実行されます。 私の最初の誤解も同じでした。catch は最初にスローされた Error を直接キャッチする、つまり、Error は promise1-2 の後に出力され、promise2-2 が配置されている then はコール スタックに追加されないと誤解していました。 しかし、実際の出力結果を観察すると、そうではないことがわかります。これは、MDN の説明の文字通りの意味が間違っていることを示しています。チェーン呼び出しは停止せず、私たちが見ていない何かを実行しました。 連鎖デフォルト処理この時点では、デフォルトの処理を知る必要があり、MDN の説明も直接引用します。 then が呼び出される Promise が、then にハンドラーがない状態 (履行または拒否) を採用する場合、then が呼び出された元の Promise の最終状態を単純に採用して、追加のハンドラーなしで新しい Promise が作成されます。 プロミスの then に対応する状態処理のコールバックがない場合、then はこのプロミスの状態を受け入れるプロミスを自動的に生成します。つまり、then は同じ状態参照を持つプロミスを返し、それを後続の呼び出しに渡します。 上記のコードの2番目のpromise部分は次のようになります。 Promise.resolve('promise2') .then(res => { console.log('promise2-1 then') 新しいエラーをスローします('モックエラー1') }) .then(res => { console.log('promise2-2 then') 新しいエラーをスローします('モックエラー2') // onRejected に注意してください }, (エラー) => { Promise.reject(err) を返します。 }) .catch(エラー => { コンソール.log(エラー) }) つまり、出力結果の promise1-2 と promise1-3 の間で promise2-2 の then が実行されるため、チェーン呼び出しは直接停止されず、promise2-2 の then が呼び出しスタックに追加されたままになります。キャッチは、直接キャッチされる最初の then によってスローされたエラーではなく、非表示の onRejected によって返される同じステータスの約束です。 略語同様に、catch(onRejected) は then(undefined, onRejected) の省略形であることを知っておく必要があります。つまり、呼び出しチェーンの前の呼び出しでエラーがなくても、catch は呼び出しスタックを直接スキップするのではなく、呼び出しスタックに入ります。 Promise.resolve('promise1') .then(res => { console.log('promise1-1 then') }) .then(res => { console.log('promise1-2 then') }) .then(res => { console.log('promise1-3 then') }) Promise.resolve('promise2') .then(res => { console.log('promise2-1 then') }) .catch(エラー => { コンソール.log(エラー) }) .then(res => { console.log('実際はpromise2-3です') }) 非同期待機最初に注意すべきことは、この記事で指定されている NodeJs および Chrome バージョンでは、f(await promise) は promise.then(f) と完全に同等であるということです。 もちろん、Promise について議論するときに、async await を無視することはできません。プロミスの状態が onResolve のときは両者の処理ロジックは同じですが、エラー処理の実行ロジックが異なります。async await でエラーが発生すると、後続の await の実行が本当に直接スキップされます。 const promiseReject = new Promise((resolve, deny) => { 拒否(新しいエラー('error')) }) const promiseResolve1 = 新しい Promise((resolve, 拒否) => { 解決('正しい') }) const promiseResolve2 = 新しい Promise((resolve, 拒否) => { 解決('正しい') }) const promiseResolve3 = 新しい Promise((resolve, 拒否) => { 解決('正しい') }) 関数demo1() { 約束拒否 .then(() => { コンソールログ('1-1') }) .catch(エラー => { コンソールログ('1-2') }) } 非同期関数demo2(){ 試す { 待つ約束拒否 約束を待つ解決1 promiseResolve2を待つ 約束を待つResolve3 } キャッチ(エラー){ コンソールログ('2-1') } } // 2-1 // 1-2 上記は、JS 非同期コード単体テストの魔法の約束の詳細です。JS 非同期コードの約束の詳細については、123WORDPRESS.COM の他の関連記事に注目してください。 以下もご興味があるかもしれません:
|
>>: VMware で Centos7 ブリッジ ネットワークを構成する手順の詳細な説明
序文最近この問題に遭遇するまで、私は UTF-8 が文字セットの問題に対する普遍的な解決策だと考えて...
この記事では、例を使用して、MySQL サーバーのスレッド数を表示する方法について説明します。ご参考...
Vue に限定されず、他の種類の SPA プロジェクトにも当てはまる問題がいくつかあります。 1....
時間に余裕を持って、過去を忘れましょう。前のセクションでは、[検索] フォームとクエリおよびリセット...
機能: 前のページまたは次のページにジャンプします。要素: ページングの基本要素は、前のページ + ...
目次1.関数内のこの方向1. 通常の機能2. コンストラクター3. オブジェクトメソッド4. イベン...
目次1. 使用方法1. 基本的な使い方2. 2番目のパラメータ - フィルター3. 3番目のパラメー...
nginx (エンジン x) は、高性能な HTTP およびリバース プロキシ サーバー、メール プ...
Linux での動的ライブラリ ファイルのファイル名は libxxx.so のようになります。ここで...
MySQLデータベースのインストールに関するメモ、みんなで共有a) MySQL ソースインストールパ...
まず、一連の概念を理解しましょう。nginx リバース プロキシとは何でしょうか?リバース プロキシ...
はい、CSS にも正規表現があります (アーメン) CSS で目立つための 2 つの強力なツール: ...
目次1. インストールパッケージ(64ビット)をダウンロードする2. MySQLデータベースをインス...
1.テーブル全体を更新します。データ行の列の値が空の場合は、別の列フィールドの値と同じにします。 ...
絶対、相対、固定位置の位置決めabsolue: 絶対配置。上、下、左、右を使用して、配置先の親要素に...