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 をインストールするための詳細なチュートリアル (パフォーマンス テスト)

推薦する

Docker で既存のイメージに基づいて新しいイメージを構築する方法

既存のイメージから新しいイメージを構築することは、Dockerfile ドキュメントを通じて行われま...

jQueryは画像追従効果を実現します

この記事では、画像フォロー効果を実現するためのjQueryの具体的なコードを参考までに紹介します。具...

Vue 基本チュートリアル: 条件付きレンダリングとリストレンダリング

目次序文1.1 機能1.2 要素の可視性を制御する方法1.3 初期レンダリングの比較1.4 スイッチ...

フロントエンドの状態管理(パート 1)

目次1. フロントエンドの状態管理とは何ですか? 2. ヴュークス3. バス4. ウェブストレージ序...

HTMLは読み取り専用のテキストボックスを実装しており、コンテンツを変更することはできません。

さっそく、コードを直接投稿します。具体的なコードは次のとおりです。 <!--方法 1: onf...

CentOS 6.5 i386 インストール MySQL 5.7.18 詳細チュートリアル

ほとんどの人はMySQLをコンパイルしてシステムディレクトリに置きますが、私のやり方はコンパイルした...

Vue3.0のさまざまなリスニング方法の包括的な概要

目次リスナー1.ウォッチエフェクト2.見る1.1 聴くための最初の方法1.2 聞く2つ目の方法1.3...

Springboot+Vue-Cropperでアバターの切り取りとアップロードの効果を実現

アバターをアップロードするにはVue-Cropperコンポーネントを使用します。参考までに具体的な内...

HTML+CSSを使用してマウスの動きを追跡する

ユーザーがプライバシーを意識するようになり、オンライン トラッキングに対する予防策を強化するにつれて...

Vueモバイル端末の適応化問題の詳細説明

1. vue uiでプロジェクトを作成する 2. 基本設定項目を選択する 3. プロジェクトを実行す...

MySqlサブクエリINの実装と最適化

目次IN が遅いのはなぜですか? INとEXISTSのどちらが速いでしょうか?効率を向上させるにはど...

MySQL でシンプルな検索エンジンを実装するためのサンプルコード

目次序文導入ngram全文パーサー全文インデックスを作成する検索方法1. 自然言語検索(自然言語モー...

MySQL公式パフォーマンステストツールmysqlslapの使い方の紹介

目次導入説明書実際の経験まとめ導入MySQL は最も人気のあるオープンソース データベースとして、さ...

Linux で time(NULL) 関数と localtime() を使用して現在の時刻を取得する方法

time(); 関数関数プロトタイプ: time_t time(time_t *timer)関数の目...