JavaScript フロントエンドのタイムアウト非同期操作に最適なソリューション

JavaScript フロントエンドのタイムアウト非同期操作に最適なソリューション

ECMAScript の Promise ES2015 と async/await ES2017 機能がリリースされて以来、非同期はフロントエンドの世界で特に一般的な操作になりました。非同期コードと同期コードが問題を処理する順序には若干の違いがあります。非同期コードを書くには、同期コードを書く場合とは異なる「意識」が必要です。

コードの実行に長い時間がかかる場合はどうなりますか?

これが同期コードの場合、「無応答」、または平易な言葉で言えば「死」と呼ばれる現象が発生しますが、非同期コードの場合はどうなるでしょうか。結果は得られないかもしれませんが、他のコードは何も起こらなかったかのように続行されます。

もちろん、実際に何も起こらなかったわけではなく、状況が異なれば異なる現象が起こるというだけです。たとえば、読み込みアニメーションのあるページは常に読み込み中のように見えます。別の例としては、データが更新されるはずなのにデータの変更が見えないページがあります。

例えば、どうやってもダイアログボックスを閉じることができない…このような現象をバグと呼びます。しかし、非同期操作プロセスが「エコー」せず、そこで静かに終了する場合もあります。誰もそれを知ることはなく、ページが更新された後は痕跡さえ残りません。

Axiosにはタイムアウト処理機能が搭載されている

Axios を使用して Web API 呼び出しを行うことは、一般的な非同期操作プロセスです。通常、コードは次のように記述されます。

試す {
    const res = axios.get(url, options); を待機します。
    //TODO 後続の業務を通常どおり続行します} catch(err) {
    // TODO フォールトトレランスを実行するかエラーを報告する}

このコードは通常はうまく機能しますが、ある日ユーザーから「なぜこんなに長く待っても応答がないのか」という苦情が寄せられます。

その後、開発者は、サーバーへの負荷が増大したため、この要求に即座に応答することが困難であることに気付きました。ユーザーの気持ちを考慮して、読み込みアニメーションが追加されます。

試す {
    読み込み中を表示します。
    const res = axios.get(url, options); を待機します。
    //TODO 通常業務} catch (err) {
    //TODO フォールトトレランス処理} finally {
    読み込みを非表示にします();
}

しかし、ある日、あるユーザーが「30 分待ったが、ぐるぐる回り続けるだけだ!」と言いました。そこで開発者は、何らかの理由でリクエストが停止していることに気付きました。この場合、リクエストを再送信するか、ユーザーに直接報告する必要があります。つまり、タイムアウト チェックを追加する必要があります。

幸いなことに、Axios はタイムアウトを処理できます。 optionstimeout: 3000を追加するだけで、この問題を解決できます。タイムアウトが発生した場合は、 catchブロックでそれを検出して処理できます。

試す {...}
キャッチ(エラー){
    if (err.isAxiosError && !err.response && err.request
        && err.message.startsWith("タイムアウト")) {
        // Axios リクエストが間違っていて、メッセージが遅延メッセージである場合 // TODO はタイムアウトを処理します}
}
ついに {...}

Axios は問題ありませんが、 fetch()を使用するとどうなるでしょうか?

fetch() タイムアウトの処理

fetch()自体にはタイムアウトを処理する機能がないため、タイムアウトを決定し、 AbortControllerを使用して「キャンセル」要求操作をトリガーする必要があります。

fetch()操作を中止する必要がある場合は、 AbortControllerオブジェクトからsignalを取得し、シグナル オブジェクトをfetch()オプションとして渡すだけです。おそらく次のようになります:

const ac = 新しい AbortController();
const {シグナル} = ac;
fetch(url, { signal }).then(res => {
    //TODO ビジネスを処理する});
 
// 1 秒後にフェッチ操作をキャンセルします setTimeout(() => ac.abort(), 1000);

ac.abort()signalにシグナルを送信し、そのabortイベントをトリガーし、その.abortedプロパティをtrueに設定します。 fetch()内部処理では、この情報を使用して要求を中止します。

上記の例はfetch()操作のタイムアウト処理を実装する方法を示しています。これを処理するためにawaitを使用する場合は、 fetch(...) setTimeout(...)を配置する必要があります。

const ac = 新しい AbortController();
const {シグナル} = ac;
タイムアウトを設定します(() => ac.abort(), 1000);
const res = await fetch(url, { signal }).catch(() => undefined);

リクエストの失敗を処理するためにtry ... catch ...を使用することを避けるために、エラーを無視するためにfetch()の後に.catch(...)が追加されます。エラーが発生した場合、 resundefined値が割り当てられます。実際のビジネス処理では、 resに識別可能なエラー情報を含めることができるように、より合理的なcatch()処理が必要になる場合があります。

ここで終了することもできましたが、各fetch()呼び出しごとにこのような長いコードを書くのは面倒なので、次のようにカプセル化しましょう。

非同期関数 fetchWithTimeout(timeout, resoure, init = {}) {
    const ac = 新しい AbortController();
    定数シグナル = ac.signal;
    setTimeout(() => ac.abort(), タイムアウト);
    return fetch(リソース、{...init、signal});
}

それでいいですか?いいえ、問題があります。

上記のコードのsetTimeout(...)でメッセージを出力すると、次のようになります。

タイムアウトを設定する(() => {
    console.log("タイムアウトです");
    ac.abort();
}、 タイムアウト);

そして、電話には十分な時間をかけましょう。

fetchWithTimeout(5000, url).then(res => console.log("success"));

出力successが表示され、5 秒後に出力It's timeout表示されます。

ちなみに、 fetch(...)のタイムアウトは処理しましたが、 fetch(...)が成功したときにtimer強制終了しませんでした。思慮深いプログラマーがどうしてこのような間違いを犯すのでしょうか?彼を殺せ!

非同期関数 fetchWithTimeout(timeout, resoure, init = {}) {
    const ac = 新しい AbortController();
    定数シグナル = ac.signal;    
    定数タイマー = setTimeout(() => {
        console.log("タイムアウトです");
        ac.abort() を返します。
    }、 タイムアウト);    
    試す {
        return await fetch(resoure, { ...init, signal });
    ついに
        タイマーをクリアします。
    }
}

完璧!しかし、問題はまだ終わっていません。

すべてがタイムアウトになる可能性がある

Axios と fetch はどちらも非同期操作を中断する方法を提供していますが、 abort機能を持たない通常の Promise の場合はどうなるでしょうか?

そのような約束に対して、私が言えるのは、彼を行かせなさい、彼が永遠にそれを続けさせなさいということだけです。どうせ私は彼を止めることはできません。でも人生は続いていくので、待ち続けることはできません!

この場合、 setTimeout()を Promise にカプセル化し、 Promise.race()を使用して「時間切れ後に待機しない」を実装できます。

Race はレースを意味するので、 Promise.race()の動作は理解しやすいですよね?

関数 waitWithTimeout(promise, timeout, timeoutMessage = "timeout") {
    タイマーを設定します。
    const timeoutPromise = 新しい Promise((_, 拒否) => {
        タイマー = setTimeout(() => 拒否(timeoutMessage)、タイムアウト);
    }); 
    Promise.race([timeoutPromise, promise]) を返します。
        .finally(() => clearTimeout(timer)); // タイマーをクリアするのを忘れないでください
}

効果をシミュレートするために Timeout を記述できます。

(非同期() => {
    const business = new Promise(resolve => setTimeout(resolve, 1000 * 10));
    試す {
        waitWithTimeout(ビジネス、1000) を待機します。
        console.log("[成功]");
    } キャッチ (エラー) {
        console.log("[エラー]", err); // [エラー] タイムアウト
    }
})();

上記は、JavaScript フロントエンドのタイムアウト非同期操作に対する完璧なソリューションの詳細な内容です。フロントエンドのタイムアウト非同期操作の解決の詳細については、123WORDPRESS.COM の他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • JavaScript 非同期操作の一般的な処理方法の概要
  • js の非同期読み込みのための 3 つのソリューション
  • JavaScriptの非同期エラーを適切に処理する方法について簡単に説明します。
  • 非同期プログラミングの例外を解決するためにJavaScriptを学んでください
  • Vue axios リクエストのタイムアウトの正しい処理

<<:  MySQL での utf8mb4 照合の例

>>:  CSS で中空マスク レイヤーを実装するサンプル コード

推薦する

パーティクルダイナミックボタン効果を実現するCSS

オリジナルリンクhttps://github.com/XboxYan/no…ボタンは、おそらく We...

Linux サービスでファイアウォールを有効にする 2 つの方法

方法は2つあります: 1. サービス方法ファイアウォールのステータスを確認します。 [root@ce...

CSSテーマを簡単に切り替える方法の詳細な説明

最近、個人の Web サイトに非常にシンプルなカラー スキーム (テーマ) スイッチャーを追加しまし...

海外の無料写真素材サイトベスト9

良い画像素材のウェブサイトを見つけるのは難しいです。特に無料です。良い写真には非常に目を引く視覚効果...

プログレッシブ ウェブ アプリ (PWA) の開発方法

目次概要必要とするアプリURL PWA にはどのような技術コンポーネントが必要ですか?マニフェストフ...

CSS3 で実装された画像ホバートグルボタン

結果:実装コードhtml <ul class="スライド"> <...

Raspberry Pi msmtp と mutt のインストールと設定のチュートリアル

1. muttをインストールするsudo apt-get install mutt 2. msmtp...

Vue でフルスクリーンを実装し、フルスクリーン終了を監視する

目次序文:実装手順:完全なソースコード:詳細情報:序文: vueでは、デフォルトページを実装し、di...

広告を閉じる効果を実現するJavascript

参考までに、Javascript を使用して広告を閉じる方法に関するケース スタディを示します。詳細...

ファイル操作のためのLinuxシステムコール

目次1. ファイルを開くパラメータの紹介2. ファイルの読み取り3. ファイルを書き込む4. 閉じる...

WeChatアプレットの手動および自動追跡の実装の詳細説明(Taro)

どの企業もユーザーベースを拡大したいのであれば、ユーザーの操作データを収集・分析する必要があり、その...

Vue 要素と Nuxt の使用に関するヒントを共有する

1. 要素時間選択提出フォーマット変換例えば 2018年9月7日金曜日 00:00:00 GMT+0...

Win10 64ビットMySQL8.0のダウンロードとインストールのチュートリアル図

公式サイトから MySQL をダウンロードしてインストールし、クライアントにログインするにはどうすれ...

MySQL データベースのパフォーマンス最適化の概要

目次なぜ最適化するのですか? ?どこから始めますか? ?解決策は何ですか? ? ?どうやって選ぶ? ...

CSS3 アドバンス LESS で星空アニメーションを実装するサンプルコード

この記事では、星空アニメーションを実現するための高度な CSS3 LESS のサンプルコードを次のよ...