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のスレッド実行の急増とクエリの遅延の問題を解決する

目次背景問題の説明原因分析CPUクエリが遅い接続数分析する拡大する総括する背景新年を迎える前は、一年...

Centos8.3、dockerデプロイメントspringbootプロジェクトの実際のケース分析

導入現在、k8s は非常に人気があり、それについて学ぶために本を購入しました。しかし、k8s では数...

最も単純な ErrorBoundary コンポーネントをカプセル化して、React 例外を処理する

序文React 16から、子コンポーネントで発生したエラーを捕捉し、エラーログを記録し、ダウングレー...

Ubuntuで余分なカーネルを削除する方法

ステップ1: 現在のカーネルを表示する 読み取る $ uname -a Linux rew 4.15...

MySQL主キー命名戦略関連

最近、データライフサイクル管理の詳細を整理していたときに、小さな問題を発見しました。それは、MySQ...

CSS が初期読み込み時の白い画面の時間に与える影響

外部 CSS ファイルを使用したレンダリング パイプライン上図では、HTML データの要求から DO...

Zabbixについて管理者ログインパスワードを忘れた場合、パスワードをリセットする

Zabbix 管理者ログイン パスワードのリセットに関する問題は次のとおりです。 1. 問題の説明:...

CSS を使用して同じ親タグの左側と右側に 2 つのボタンを配置する方法

この記事では、主に同じ親タグの左側と右側にある 2 つのボタンの CSS レイアウト方法を紹介し、皆...

vue-resource インターセプターの使用に関する詳細な説明

序文インターセプター最近のフロントエンド フレームワークでは、インターセプターは基本的に非常に基本的...

VMWare14.0.0のUbuntu仮想マシンで共有フォルダを設定する

これは私の最初のブログ投稿です。時間の制約があるため、どのようにフォーマットすればよいかわかりません...

Web ページのエンコーディングで gbk や gb2312 ではなく utf-8 が使用されるのはなぜですか?

選択肢がある場合は、UTF-8を使用することをお勧めします。実際、Windows システム自体のプロ...

URL を入力すると、バックグラウンドでは具体的に何が起こるのでしょうか?

ソフトウェア開発者は、ネットワーク アプリケーションがどのように動作するかを階層的に完全に理解してい...

バッチファイルを処理するLinuxの1行コマンドの詳細な説明

序文最良の方法は、あなたが思いつく最も速い方法ではないかもしれません。職場で一時的に使用するスクリプ...

ウェブページ内でウェブテーブルやdivレイヤーが引き伸ばされる問題の解決策

<br />Web ページをデザインするときには、いつも不快なことに遭遇します。最も一般...

CentOS での Django プロジェクトのデプロイに関する詳細なチュートリアル

基本環境パゴダ設置サービスパゴダにインストールされた[Pythonプロジェクトマネージャー]パゴダに...