jQuery の $.ajax始める前に、私の js 非同期の旅について話しましょう。私が学生だった頃は、jQuery がまだ王者でした。私が直接触れ、最も頻繁に使用した非同期操作はネットワーク リクエストでした。$.ajax を使って世界中を飛び回り、大学 2 年生から卒業後のほぼ半年までずっと付き添っていました。 $.ajax( "/xxx" ) .done(関数() { // 成功しました!!! 何かしてください... }) .fail(関数() { // 失敗!!! 何かしてください... }) .always(関数() { // 読み込みが完了しました。 }); $.ajax が非常に便利であることは否定できません。リクエストが 1 つしかないほとんどのシナリオでは、$.ajax は十分に機能し、素晴らしいです。 しかし、大きな問題があります。それは、リクエスト チェーンに直面したときに非常に煩わしくなるということです。たとえば、1 つのリクエストが別のリクエストの結果に依存している場合、2 つは問題にならないかもしれませんが、5 つまたは 8 つある場合は、自殺したくなるかもしれません。 。 。 $.ajax('/xxx1') .done(関数() { // 成功しました!!! 何かしてください... $.ajax('/xxx2') .done(関数() { // 成功しました!!! 何かしてください... $.ajax('/xxx3') .done(関数() { // 成功しました!!! 何かしてください... $.ajax('/xxx4') .done(関数() { // 成功しました!!! 何かしてください... $.ajax('/xxx5') .done(関数() { // 成功しました!!! 何かしてください... // もっと... }) .fail(関数() { // 失敗!!! 何かしてください... }) .always(関数() { // 読み込みが完了しました。 }); }) .fail(関数() { // 失敗!!! 何かしてください... }) .always(関数() { // 読み込みが完了しました。 }); }) .fail(関数() { // 失敗!!! 何かしてください... $.ajax('/xxx6') .done(関数() { // 成功しました!!! 何かしてください... $.ajax('/xxx7') .done(関数() { // 成功しました!!! 何かしてください... // もっと.... }) .fail(関数() { // 失敗!!! 何かしてください... }) .always(関数() { // 読み込みが完了しました。 }); }) .fail(関数() { // 失敗!!! 何かしてください... }) .always(関数() { // 読み込みが完了しました。 }); }) .always(関数() { // 読み込みが完了しました。 }); }) .fail(関数() { // 失敗!!! 何かしてください... }) .always(関数() { // 読み込みが完了しました。 }); }) .fail(関数() { // 失敗!!! 何かしてください... }) .always(関数() { // 読み込みが完了しました。 }); すみません、こんなに重ねられるとは知りませんでした。 。 。しかし、実際には、TM ではこのようなプロセスが頻繁に発生します。教えてください、これは製品のせいではありませんよね? ? ?勉強が苦手なのは自分のせいだ このような連鎖的な操作には誰もがイライラすると思います。コードの可読性については話さないようにしましょう。毎日変わる製品要件を考えてみましょう。おそらく、リクエスト 1 の後にリクエスト 2、リクエスト 3 が続いたでしょう。その後、製品マネージャーはプロセスが適切ではないと判断し、リクエスト 2、リクエスト 3、リクエスト 1 になりました。これをどのように変更できるでしょうか。なぜ axios、await、async を使用しないのかと疑問に思う人もいるかもしれません。プロジェクト コードは 2008 年に書かれた JSP であることに留意する必要があります。 。 。 。半年以上もぐずぐずしていた後、大きな転機が訪れました。私が書いた新しいプロジェクトは Vue に切り替わり、互換性をある程度放棄するようになり、私はすぐに飛び立ちました。 。 。 Webpack時代の始まり新しいプロジェクトは Vue + Webpack です。axios、await、async を直接配置しました。これでコードは非常に使いやすくなり、ネストされた N 層のコードがなくなりました。 r1 を待機します。 (r1.xxx === 1)の場合{ r2 を待機します。 r3 を待機します。 // 何かをする.... } それ以外 { r4 は r1 を待機します。 r5 は r4 を待機します。 // 何かをする.... } // 何かをする.... しかし、上記のコードには問題があります。タスクがエラーを報告すると、コードは直接終了します。 。 。これは期待に応えていないので、try catchを追加しましょう。 r1 とします。 試す { r1 = doSomthing1() を待機します。 } キャッチ (e) { // 何かをする... 戻る; } もし(r1){ (r1.xxx === 1)の場合{ r2とします。 試す { r2 = doSomthing2(r1) を待機します。 } キャッチ (e) { // 何かをする... 戻る; } (r2) の場合 { r3 とします。 試す { r3 = doSomthing3(r2) を待機します。 } キャッチ (e) { // 何かをする... 戻る; } // 何かをする... } } それ以外 { r4 とします。 試す { r4 = doSomthing4(r1) を待機します。 } キャッチ (e) { // 何かをする... 戻る; } (r4) の場合 { r5 とします。 試す { r5 = doSomthing5(r4) を待機します。 } キャッチ (e) { // 何かをする... 戻る; } } // 何かをする... } // 何かをする... } ? ? ? 最適化されていますが、最適化されていないのと同じです。 。 。 この時点で、賢い友人たちは「これは何のパンケーキですか?」と尋ねると思います。そして、鈍い友人たちはすでにこの問題をどう解決するか考え始めています。 。 。 約束について深く考えるPromiseの定義を見てみましょう /** * 非同期操作の完了を表します */ インターフェース Promise<T> { /** * Promise の解決および/または拒否のためのコールバックを添付します。 * @param onfulfilled Promise が解決されたときに実行されるコールバック。 * @param onrejected Promise が拒否されたときに実行するコールバック。 * @returns 実行されたコールバックの完了を示す Promise 。 */ then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>; /** * Promise の拒否のみのコールバックを添付します。 * @param onrejected Promise が拒否されたときに実行するコールバック。 * @returns コールバックの完了に対する Promise。 */ catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult>; } then と catch は両方とも新しい Promise を返します。この問題の解決方法は既に多くの人がわかっていると思います。エラーを報告するため、try catch を使用する必要があります。では、エラーを報告しない結果を返してはどうでしょうか。やるだけ ネストをなくす関数 any(promise) { promise.then((v) => v).catch((_) => null); を返します。 } これは完全に解決されましたか? ? ?値があるかどうかで成功かどうか判断すれば、try catch を書く必要はないのですが、このようなコードはちょっと使いにくいです。then が void を返したらそれで終わりです。片方は undefined でもう片方は null です。判断しても無駄です。改善しましょう。 関数 any(promise) { 返品の約束 .then((v) => ({ ok: v, hasErr: false })) .catch((e) => ({ err: e, hasErr: true })); } 言葉を使う const r = any(doSomething()) を待機します。 r.hasErrの場合{ コンソールログに出力します。 戻る; } コンソールにログ出力します。 完璧だと思いませんか?すぐに友達に宣伝しましょう。 友達:? ? ?これは何のパンケーキですか? 要りません。 私: これは私が書きました。非同期環境では非常にうまく機能します。try catch などをネストする必要はありません。 。 。 友人:わかった。次回使うよ。 誰もが、お互いのコードを軽蔑し合い、サードパーティのライブラリでない限りは、できれば誰も使わない、といった状況に遭遇したことがあるはずです。 。 。 js を待つこの優雅さを評価したのは私だけだと思っていました。状況は好転しました。ある日、GitHub を閲覧していたところ、私のものと似たもの、await-to-js を見つけました。数行のコードから、私と同じ執着が明らかになりました。 // 以下は最新のコードです/** * @param { プロミス } プロミス * @param { Object= } errorExt - errオブジェクトに渡すことができる追加情報 * @return { プロミス } */ エクスポート関数を<T, U = エラー> ( プロミス: Promise<T>, errorExt?: オブジェクト ): Promise<[U, undefined] | [null, T]> { 返品の約束 .then<[null, T]>((データ: T) => [null, データ]) .catch<[U, 未定義]>((err: U) => { if (errorExt) { オブジェクトにerrを代入します。 } [err, undefined]を返します。 }); } エクスポートのデフォルト; 次に使用例を貼り付けます 'await-to-js' からインポートします。 // CommonJS (つまり NodeJS 環境) を使用する場合は、次のようになります。 // 定数 to = require('await-to-js').default; 非同期関数 asyncTaskWithCb(cb) { err、user、savedTask、notification を実行します。 [ err, user ] = (UserModel.findById(1)) を待機します。 if(!user) return cb('ユーザーが見つかりません'); [ err, savedTask ] = await to(TaskModel({userId: user.id, name: 'Demo Task'})); if(err) return cb('タスクの保存中にエラーが発生しました'); 通知が有効になっている場合 [ err ] = await to(NotificationService.sendNotification(user.id, 'タスクが作成されました')); if(err) return cb('通知の送信中にエラーが発生しました'); } 保存されたタスクの割り当てユーザーIDがユーザーIDと等しい場合、 [ err, notification ] = await to(NotificationService.sendNotification(savedTask.assignedUser.id, 'タスクが作成されました')); if(err) return cb('通知の送信中にエラーが発生しました'); } cb(null、保存されたタスク); } 非同期関数 asyncFunctionWithThrow() { const [err, user] = (UserModel.findById(1)) を待機します。 if (!user) throw new Error('ユーザーが見つかりません'); } 感情は戻ってきて、もう巣になっていないのでしょうか? 。 。 友人に前のコード行を使用させるには、しぶしぶ await-to-js を推奨し、github に投稿するしかありません。友人: 800 個以上のスター (追記: 現在 2K+) 品質は信頼できます。例を見てみました。まあ、とても良くて完璧です。次の例に戻ります。 。 。次に何が起こったかについては、あまり言う必要はありません。また、自分のコードもすべて await-to-js に置き換えました。 。 。 私は世界を初恋のように扱うが、初恋は私を何千倍も傷つける 要約する私が実装したバージョンには、実はいくつか問題があります。JS のような柔軟な言語では、戻り値を変更すると、他の人が私のバージョンをコピーするだけですみます。型が十分に厳密ではありません。TS に入れれば、小さな問題としか言えません。新しく追加された ok、err、hasErr は少しケースを追加しますが、致命的ではありません。 await-to-js の設計哲学の一部、つまり、なぜエラーが成功ではなく配列の最初の位置に配置されるのか、は非常に明確です。つまり、成功に自信を持ち、間違いの痛みを忘れるのではなく、間違いを常に覚えておき、間違いを最優先するのです。 const [, 結果] = (iWillSucceed()) を待機します。 参考文献
これで、JS で async await をエレガントに使用する方法についての記事は終了です。JS で async await をエレガントに使用する方法の詳細については、123WORDPRESS.COM の以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。 以下もご興味があるかもしれません:
|
>>: SpringBoot プロジェクトの Docker 環境を実行するときに発生する無限再起動問題の詳細な説明
<br />セマンティクス化は一言で説明することはできないし、まだ公式かつ厳密な定義もあ...
WeChatアプレットでタブバーを設定すると、重要なコンテンツがブロックされ、iPhoneXなどの異...
要素の両端を揃える配置レイアウトは、実際の開発のいたるところで見られます。これは、フレックスレイアウ...
環境Linux 3.10.0-693.el7.x86_64 Docker バージョン 18.09.0...
標準 CSS3 を使用して要素の影の効果を実現するには、2 つの手順があります。1 つ目は一般的なb...
Dockerfile は、イメージをビルドするために使用されるテキスト ファイルです。テキスト コン...
目次1. axiosをインストールする2. アクシオスの使用1.ホームページでaxiosを参照する2...
最初の方法: skip-grant-tables: 非常に便利なmysql起動パラメータ非常に便利な...
目次1. レンダリング2. データをバインドし、ツリーテーブルにラベルを追加する3. すべてのコード...
CSS 疑似要素を使用して要素を制御する場合、一部の要素のスタイルを変更する必要があることがよくあり...
Linuxでyumを入力すると、プロンプトが表示されます: -bash: /usr/bin/yum:...
導入私はしばらくの間、postgresql データベースを使用していました。クラウドに移行した後、自...
この記事は主に、MySQLを再インストールする際のクリーンでないアンインストールのさまざまな問題をま...
トリガー:トリガーの使用シナリオと対応するバージョン:トリガーは次の MySQL バージョンで使用で...
目次1. はじめに2. オンデマンド属性モード3. 乱雑な遅延読み込み属性パターン4. クラスの唯一...