JavaScript 中断要求に対するいくつかの解決策の詳細な説明

JavaScript 中断要求に対するいくつかの解決策の詳細な説明

1 約束

Promise の欠点の 1 つは、一度作成するとキャンセルできないため、基本的に Promise を終了できないことです。

ただし、呼び出しチェーンを中断するか、Promise を中断することで、リクエストの中断をシミュレートできます。

呼び出しチェーンを中断する

呼び出しチェーンを中断すると、then/catch が実行された後、後続のチェーン呼び出し (then、catch、finally を含む) は実行されなくなります。

このメソッドは、then/catch で新しい Promise インスタンスを返し、それを保留状態に保持します。

新しい Promise((resolve, 拒否) => {
    タイムアウトを設定する(() => {
        解決('結果');
    });
}).then(res => {
    // 特定の条件が満たされた場合、呼び出しチェーンを中断するために保留中の Promise インスタンスを返します if (res === 'result') {
        新しい Promise(() => {} を返します。
    }
    console.log(res); // 印刷なし }).then(() => {
    console.log('then は実行されません'); // 印刷されません}).catch(() => {
    console.log('catch not performed'); // 印刷なし}).finally(() => {
    console.log('最終的に実行されませんでした'); // 印刷されません});

約束を破る

Promise を中断することは、Promise を中止することと同じではありません。Promise は終了できないためです。

ここでの中断とは、保留中の約束を適切なタイミングで拒否することを意味します。たとえば、一般的なアプリケーション シナリオでは、ネットワーク要求にタイムアウトを設定し、タイムアウトが発生すると中断します。

通常どおり、setTimeout を使用してネットワーク リクエストをシミュレートします。しきい値は Math.random() * 3000 に設定されており、これは結果が 3 秒以内に返されることを意味します。

const request = new Promise((resolve, deny) => {
  タイムアウトを設定する(() => {
    解決('サーバーデータを受信しました')
  }, Math.random() * 3000)
})

2 秒を超えるとネットワーク タイムアウトを意味すると仮定すると、タイムアウト処理関数をカプセル化できます。

ネットワーク リクエストに必要なイベントはランダムであるため、Promise.race メソッドを使用してタイムアウト拒否の目的を達成できます。

const timeoutReject = (p1, タイムアウト = 2000) => {
    const p2 = new Promise((resolve, deny) => {
        タイムアウトを設定する(() => {
            拒否('ネットワークタイムアウト');
        }、 タイムアウト);
    });
    Promise.race([p1, p2]) を返します。
};

timeoutReject(リクエスト)。その後(res => {
    コンソールログ(res);
}).catch(エラー => {
    コンソールログ(エラー);
});

中止メソッドのラッピング - Axios の CancelToken を模倣

上記の実装は、ネットワーク タイムアウトだけでなく、Promise を中断する方法が多数あるため、柔軟性がありません。

Axios で CancelToken のコア ソース コードを模倣し、ユーザーがいつでも呼び出せる中止メソッドをパッケージ化することができます。

関数abortWrapper(p1) {
    中止させる;
    const p2 = new Promise((resolve, deny) => {
        中止 = 拒否;
    });
    // 解決も拒否もない場合、p2 のステータスは常に保留中になります
    定数 p = Promise.race([p1, p2]);
    p.abort = 中止;
    p を返します。
}

リクエストを中止する
req.then(res => {
    コンソールログ(res);
}).catch(エラー => {
    コンソールログ(エラー);
});

タイムアウトを設定する(() => {
    // 手動で req.abort を呼び出して、p2 のステータスを [rejected] に変更します。
    req.abort('手動中止リクエスト');
}, 2000);

このようなカプセル化の主な目的は、Promise の外部で解決または拒否を制御できるようにして、ユーザーがいつでも手動で解決 (trigger .then) または拒否 (trigger .catch) を呼び出すことができるようにすることです。

Promise リクエストが中断されても、Promise は終了せず、ネットワーク リクエストが返される可能性がありますが、その時点ではリクエストの結果は気にしなくてよいことに注意してください。

2 RXJS 登録解除メソッド

Rxjs 自体が登録解除メソッドを提供します。

stream1$ = new Observable(observer => { とする
    タイムアウトをsetTimeout(() => {
        observer.next('観測可能なタイムアウト');
    }, 2000);

    戻り値 () => {
        タイムアウトをクリアします(タイムアウト);
    }
});
disposable を stream1$.subscribe(value => console.log(value)) にします。
タイムアウトを設定する(() => {
    使い捨て。購読解除();
}, 1000);

3 Axios キャンセルトークン

Axios の CancelToken は 2 つの方法で使用できます。

  • 方法1
'axios' から axios をインポートします。
CancelToken は axios.CancelToken に置き換えられます。
const ソース = CancelToken.source();

axios.get('/user/12345', {
  キャンセルトークン: ソース.token
}).catch(関数(スロー) {
  もし(axios.isCancel(スロー)){
    console.log('リクエストがキャンセルされました', throwed.message);
  } それ以外 {
    // エラーを処理する
  } 
});

source.cancel('ユーザーによって操作がキャンセルされました。');
  • 方法2
'axios' から axios をインポートします。
CancelToken は axios.CancelToken に置き換えられます。

// リクエストを中断する方法を保存するために cancel などの変数を作成します。let cancel;

axios.get('/user/12345', {
  キャンセルトークン: 新しいキャンセルトークン(関数executor(c) {
    cancel = c; // パラメータ c を cancel に割り当てる
  })
});

// cancel が関数であるかどうかを判断し、axios が CancelToken をインスタンス化したことを確認します
if (typeof cancel === 'function') {
    キャンセル();
    キャンセル = null;
}

CancelToken コア ソースコード: (axios/lib/cancel/CancelToken.js)

'厳密な使用';

var キャンセル = require('./Cancel');

/**
 * `CancelToken` は、操作のキャンセルを要求するために使用できるオブジェクトです。
 *
 * @クラス
 * @param {Function} executor 実行者関数。
 */
関数CancelToken(エグゼキュータ) {
  if (typeof executor !== 'function') {
    throw new TypeError('executor は関数である必要があります。');
  }

  var 解決Promise;
  this.promise = 新しいPromise(関数promiseExecutor(resolve) {
    解決の約束 = 解決します;
  });

  var トークン = this;
  実行者(関数キャンセル(メッセージ) {
    if (トークン.理由) {
      // キャンセルはすでにリクエストされています
      戻る;
    }

    token.reason = 新しいCancel(メッセージ);
    トークンを解決します。
  });
}

/**
 * キャンセルが要求された場合は `Cancel` をスローします。
 */
CancelToken.prototype.throwIfRequested = 関数throwIfRequested() {
  if (this.reason) {
    this.reason をスローします。
  }
};

/**
 * 新しい`CancelToken`と、呼び出されると、
 * `CancelToken` をキャンセルします。
 */
CancelToken.source = 関数ソース() {
  var キャンセル;
  var token = new CancelToken(function executor(c) {
    キャンセル = c;
  });
  戻る {
    トークン: トークン、
    キャンセル: キャンセル
  };
};

module.exports = キャンセルトークン;

Axios の下部では、CancelToken のコア ソース コードに具体化されたアイデアが、上記の Promise パッケージの abort メソッドを中断するというアイデアと一致していることがわかります。

Axios は、resolve を外部から手動で呼び出し (ユーザーが cancel メソッドをトリガー)、resolve が呼び出されると、promise の then メソッドをトリガーするだけです。promise.then のソース コードを見てみましょう: (axios/lib/adapters/xhr.js)

if (config.cancelToken) {
  // キャンセル処理
  config.cancelToken.promise.then(関数onCanceled(キャンセル) {
    if (!リクエスト) {
      戻る;
    }

    リクエストを中止します。
    拒否(キャンセル);
    // クリーンアップ要求
    リクエスト = null;
  });
}

then メソッド内で abort メソッドが実行されてリクエストがキャンセルされ、reject が呼び出されて外側の promise が失敗することがわかります。

JavaScript 割り込み要求の詳細な解決策をいくつか紹介したこの記事はこれで終わりです。より関連性の高い js 割り込み要求コンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • クッキーを書き込むJavaScriptコードライブラリcookieLibrary.js
  • JS コードベースをゼロから構築する
  • Java FastJsonの簡単な使い方
  • Vue.js パフォーマンス最適化 N 個のヒント (収集する価値あり)
  • AngularJSは、テーブルの一部の列を拡大縮小するサンプルコードを実装します。
  • JavaScript は、シンプルな虫眼鏡の最も完全なコード分析を実装します (ES5)
  • シンプルなカルーセルの最も完全なコード分析を実装するJavaScript(ES6オブジェクト指向)
  • シンプルなカルーセル チャートを実装するための JavaScript の最も完全なコード分析 (ES5)
  • シンプルなショッピングカートの最も完全なコード分析を実装する JavaScript (ES6 オブジェクト指向)
  • JavaScript コードベースをよりクリーンにする 5 つの方法

<<:  mysql-connector-java.jar パッケージのダウンロード プロセスの詳細な説明

>>:  Docker に influxdb をインストールするための詳細なチュートリアル (パフォーマンス テスト)

推薦する

MySQL クエリ キャッシュのグラフィカルな説明

目次1. 原則の概要クエリキャッシュシステム変数1. クエリキャッシュを持つ2. クエリキャッシュ制...

MySQL の order by ステートメントの最適化方法の詳細な説明

この記事では、ORDER BY文の最適化について学びます。その前に、インデックスの基礎的な理解が必要...

Ubuntu16.04 インストール mysql5.7.22 グラフィックチュートリアル

VMware12.0+Ubuntu16.04+MySQL5.7.22 インストールチュートリアルの詳...

ubuntu20.04 LTS システムのデフォルト ソース ソース リスト ファイルの変更

誤って source.list の内容を変更し、一連のエラーが発生した場合は、デフォルトのソース フ...

WeChatアプレットがテキストスクロールを実装

この記事の例では、WeChatアプレットでテキストスクロールを実装するための具体的なコードを参考まで...

Linux に JDK1.8 をインストールするための詳細なチュートリアル

1. 設置前の清掃 rpm -qa | grep jdk rpm -qa | grep gcj yu...

Windows に MySQL をインストールする方法のグラフィック チュートリアル

概要: この記事では主に、Windows 環境に MySQL をインストールする方法について説明しま...

JavaScriptでマクロを使用する方法

言語では、DSL を実装するためにマクロがよく使用されます。マクロを使用すると、開発者は JSX 構...

Vue.jsはシンプルな折りたたみパネルを実装します

この記事では、Vue.jsの具体的なコードを共有して、シンプルな折りたたみパネルを実装する例を紹介し...

CSS の画像パスの問題に関する議論 (同じパッケージ/異なるパッケージ)

CSS ファイルでは、背景を使用する、つまり背景画像を追加する必要がある場合があります。これは通常、...

Mac で Docker を使用して Oracle をデプロイする方法

Mac で Docker を使用して Oracle をデプロイする方法まずdockerをインストール...

リバースプロキシ設定を実装するためのユニバーサルnginxインターフェース

1. プロキシサーバーとは何ですか?プロキシ サーバーは、クライアントが要求を送信すると、それを直接...

mysql5.6.8 ソースコードのインストールプロセス

カーネル: [root@opop ~]# cat /etc/centos-release CentO...

ログインボックスのメールプロンプトを実装するネイティブJS

この記事では、登録またはログイン時に電子メール アドレスを入力する際のドロップダウン プロンプトのネ...

CSS3 rgb と rgba (透明色) の使い方の詳しい説明

誰もが色にとても敏感だと思います。私たちの目が見るところにはどこにでも色があります。では、CSS で...