JS の Promise に中止関数を追加する方法

JS の Promise に中止関数を追加する方法

概要

Promise には、保留、解決、拒否の 3 つの状態しかありません。非同期 Promise が発行されると、待機 (保留) した後は、最終的に成功または失敗することしかできず、途中でキャンセル (中止) することはできません。

Promise に中止機能を提供するには、次の 2 つの方法があります。

  • 手動で中止を実装します。キャンセルがトリガーされた後、非同期で返されたデータは直接破棄されます (手動実装は比較的安全です)
  • ネイティブ メソッド AbortController を使用してリクエストを中断します (実験的なメソッド、互換性あり、IE ではサポートされていません)

手動でabortメソッドを実装するには2つのモードがあります。どちらもpromiseインターフェースを使用して間接的に実装します。

プロミスレースメソッド

PromiseWithAbort = function(promise){
    _abort = null とします。
    Pabort = new Promise((res,rej)=>{とする
      _abort = function(reason ='abort !'){
        console.warn(理由);
        rej(理由);
      }
    });

    race = Promise.race([promise,Pabort]) とします。
    レースを中止します。
    コンソールにログ出力します。
    復帰レース;
  }

p1 = new Promise(res=>{
   タイムアウトを設定します(()=>{
      res('p1 成功');
   },2000)
})

testP = PromiseWithAbort(p1); とします。

testP.then(res=>{
  console.log('成功:',res);
},エラー=>{
  console.log('エラー:',エラー);
})

テストPを中止します。

// 結果: 拒否: 中止!

約束の再パッケージ化

クラスPromiseWithAbort {
    コンストラクタ(fn){
      _abort = null とします。
      _p = new Promise((res,rej)=>{ とする
        fn.call(null,res,rej);
        _abort = function(error='abort'){ rej(error); }
      })

      _p.abort = _abort;
      _p を返します。
    }
  } 


testP = new PromiseWithAbort((res,rej)=>{ とする
    タイムアウトを設定する(() => {
      レス(1);
    },1000);
  });

 testP.then(r=>{
    コンソールにログ出力します。
  },r=>{
    console.log('rej:',r);
  });

  テストPを中止します。
//結果: rej: 中止

中止コントローラ

(これは DOM 仕様に属する実験的な機能であり、一部のブラウザではまだ開発中です。) AbortController インターフェイスは、必要に応じて 1 つ以上の DOM 要求を中止できるコントローラ オブジェクトを表します。

// フェッチ要求を中断する let controller = new AbortController();
  シグナルを controller.signal とします。

 fetch('https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally',{signal}).then(r=>{
    コンソールログr;
  });

  コントローラーを中止します。
// 結果: キャッチされませんでした (promise 内) DOMException: ユーザーがリクエストを中止しました。
//Promise を中断する
クラスPromiseWithAbortController {
  コンストラクタ(fn,{シグナル}){
    if (シグナル && signal.aborted) {
      Promise.reject(新しいDOMException('Aborted','AbortError'))を返します。
    }

    _p = new Promise((resolve,reject)=>{ とする
      fn.call(null、解決、拒否);
      if(シグナル){
        シグナル.addEventListener('abort',()=>{
          拒否(新しいDOMException('Aborted','AbortError'));
        })
      }
    });

    _p を返します。
  }
}
コントローラーを新しいAbortController()にします。
  シグナルを controller.signal とします。
testP2 = new PromiseWithAbortController((r,j)=>{ とする
  タイムアウトを設定する(() => {
    r('成功');
  }, 1000);
}、{信号});

testP2.then(r=>{
    コンソールにログ出力します。
  },r=>{
    console.log('rej:',r);
  });

  コントローラーを中止します。
  // 結果: rej: DOMException: 中止

Axiosプラグインにはキャンセル機能が付属しています

//1. ソーストークンを使用する
CancelToken は axios.CancelToken に置き換えられます。
const ソース = CancelToken.source();

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

axios.post('/user/12345', {
  名前: '新しい名前'
}, {
  キャンセルトークン: ソース.token
})

// リクエストをキャンセルします(メッセージパラメータはオプションです)
source.cancel('ユーザーによって操作がキャンセルされました。');

//2. 送信関数を通じて
CancelToken は axios.CancelToken に置き換えられます。
キャンセルする;

axios.get('/user/12345', {
  キャンセルトークン: 新しいキャンセルトークン(関数executor(c) {
    // 実行関数はキャンセル関数をパラメータとして受け取ります
    キャンセル = c;
  })
});

// リクエストをキャンセルする
キャンセル();

//メイン: 同じトークンを使用するリクエストはまとめてキャンセルできます

Axios は現在のプロジェクトで最も頻繁に使用されているため、リクエストをキャンセルしても問題ありません。互換性上の理由から、DOM 指定の AbortController は推奨されません。自分で実装する必要がある場合は、この記事の最初の 2 つの方法 (Promise 競合方法と Promise 再パッケージ化方法) の方が安全です。

以上がJSがpromiseにabort関数を追加する方法の詳細です。JSの詳細については、123WORDPRESS.COMの他の関連記事にも注目してください。

以下もご興味があるかもしれません:
  • JavaScript Promise の徹底解説
  • JavaScript における Promise の詳細な説明
  • フロントエンドJavaScriptの約束
  • JS 9 Promise 面接の質問
  • JavaScriptのPromiseを徹底的に理解する

<<:  Tomcat クラスローダーの実装方法とサンプルコード

>>:  MySQL を解凍してインストールおよび完全に削除する方法の詳細なグラフィック説明

推薦する

JavaScript モバイル H5 画像生成ソリューションの説明

現在、WeChatパブリックアカウントの運用活動が多く、写真を生成する必要があります。生成された写真...

Node.js でのブレークポイント再開の実装

序文通常のビジネスニーズ: 写真、Excel などをアップロードします。結局のところ、数 MB のサ...

JSはスネークゲームを実装する

目次1. 初期化構造2. 蛇の色のレンダリング3. ヘビの動き4. ヘビの死を判定する方法 ヘビの死...

Intelli Idea で Tomcat 設定が見つからない問題の解決方法

2日前に新しい会社に入社しました。その会社ではIntelli Ideaを使っています。Eclipse...

Vue3+Vantコンポーネントを使用してアプリの検索履歴機能を実装する(サンプルコード)

現在、新しいアプリプロジェクトを開発中です。私にとっても初めてのアプリ開発です。チームで調査と検討を...

MySQLテーブル名の大文字と小文字を区別しない設定方法の詳細な説明

デフォルトでは、Linux の MySQL はテーブル名の大文字と小文字を区別します。 MySQL ...

面接官がmysqlのcharとvarcharの違いを尋ねたとき

目次charとvarcharの違いcharとvarcharの違い上記は、MySQL における cha...

ApacheBench でマルチ URL をサポートする方法

標準の ab は単一の URI でのストレス テストのみをサポートしており、実際のニーズを満たしてい...

tomcat デプロイメント プロジェクトの実装と IDEA との統合

目次Tomcat でプロジェクトを展開する 3 つの方法プロジェクトをwebappsディレクトリに直...

Vueプロジェクトウォッチで関数が繰り返しトリガーされる問題の解決

目次問題の説明:解決策1解決策2問題の説明:ページ A と B の 2 つがあり、各ページにはget...

SQL インジェクションのある Web サイトを見つける方法 (必読)

方法 1: Google の詳細検索を使用します。たとえば、次に示すように.asp?id=9などの ...

動的な背景グラデーション効果を実現するCSS3

CSS3 を学ぶということは、新しい機能と基本的な理論に慣れることを意味します。この記事では、ケー...

MySQL ディープ ページング (数千万のデータを素早くページ分割する方法)

目次序文場合最適化まとめ序文バックエンド開発では、一度に大量のデータがロードされ、メモリやディスク ...

MySQL データベースのステートメント ワイルドカード ファジー クエリの概要

MySQL エラー: パラメータ インデックスが範囲外です (1 > パラメータ数、つまり 0...

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

MariaDB データベース管理システムは MySQL のブランチであり、主にオープンソース コミュ...