JavaScriptはPromiseを使用して複数の繰り返しリクエストを処理します

JavaScriptはPromiseを使用して複数の繰り返しリクエストを処理します

1. なぜこの記事を書くのですか?

重複リクエストの処理に関する記事をたくさん読んだことがあるでしょう。そのほとんどは、応答が返される前に重複リクエストを返す方法と、スロットリング/アンチシェイクを使用して頻繁なユーザー操作を間接的に回避する方法の 2 つのバージョンに分かれています。最近使用してみると、この 2 つのバージョンには、いくつかのシナリオではまだ制限があることがわかりました。

2. 問題のシナリオ

図に示すように、名刺コンポーネントは h5 ページの上部と下部に表示されます。これらの名刺の情報は、インターフェースを通じて取得されます。このコンポーネントが現在のページで初期化されると、2 つの繰り返しリクエストが発生します。

この時点で、いくつかの選択肢に直面することになります。

1. 重複したリクエストを処理しないでください。

  • デメリット1: 不必要なリソースの浪費を引き起こし、サーバーの負荷が増大する
  • デメリット 2: ブラウザの同時 HTTP リクエスト数には制限があります。ページの最初の画面に対するリクエストが多く、階層的な読み込みが行われていない場合、リクエストのブロックが発生しやすく、ユーザーがそもそもメインコンテンツを見る能力に影響を与えます。

2. 重複したリクエストを直接返します。これはいくつかの記事でも実践されていますが、このアプローチには、後続の繰り返しリクエストが無効なリクエストであると直接判断されるという制限があります。

  • 無効なリクエストのシナリオ: ユーザーがクエリまたは保存のボタンをクリックします。リクエスト結果が返される前は、基本的に後続のクリックは無効なリクエストと見なされ、ブロックされる必要があります。もちろん、この問題はボタンにスロットル/手ぶれ防止機能を追加することで回避できます。
  • 現在のシナリオには適用できない理由: 両方の名刺コンポーネントは、レンダリングするためにデータを必要とします。2 回目の繰り返しリクエストが返された場合、いずれかのコンポーネントの名刺にはデータが含まれません。

3. コンポーネントからリクエストを抽出し、親ビジネス ページに配置して、それをコンポーネントに props として渡します。

  • 利点: 2 つのコンポーネントが 1 つのリクエストでデータのコピーを共有できます。
  • 制限事項: 単一のビジネス ページにのみ適用されます。実際、このコンポーネントは多くのビジネス ページで使用されています。要求された関数がパブリック API に抽出された場合でも、各ビジネス ページが初期化されるときに 1 回呼び出され、その後コンポーネントに props として渡される必要があります。

3. 解決策

コアアイデア

  • handleListの配列を初期化する
  • リクエストを送信する前に、入力パラメータが同じかどうかに基づいて、重複リクエストかどうかを判断します。
    • 繰り返しのないリクエスト: リクエストパラメータとリクエストによって返されたPromiseを配列に追加します。
    • リクエストを繰り返す: findを使用して対応するPromiseを直接返す
  • リクエストが完了したら、handleList に以前追加されたリクエスト情報を削除します。

このソリューションは、axios、jq、fetch、またはアプレット リクエストのいずれを使用する場合でも、何にでも使用できます。実装の原理は次のとおりです。使用するときは、対応するリクエスト時間に対応するコードを配置するだけです。

コードサンプル

let handleList = [] // リクエストリスト/**
 * リクエストをシミュレート * @author waldon
 * @日付 2020/6/9
 */
定数httpRequest = () => {
  新しいPromise((resolve) => {を返す
    タイムアウトを設定する(() => {
      解決(`リクエストは成功しました、タイムスタンプ: ${new Date().getTime()}`)
    }, 1000)
  })
}
/**
 * リクエスト関連の処理 * @author waldon
 * @日付 2020/6/9
 * @param {String} URL -
 * @param {Object} requestObj - リクエストパラメータ * @returns {Promise} - リクエストプロミス
 */
関数 requestTest(url, requestObj = {}) {
  // 入力パラメータは一般的に複雑な型を含まないため、シリアル化比較には JSON.stringify で十分です。 // 制限の 1 つは、入力パラメータの順序が変わるため、判定に影響が出ることです。ただし、この特別な変更は、繰り返しのリクエストでは通常発生しません。 // このような要求がある場合は、他の再帰比較 API に切り替えてください。Lodash にも同様の API があります。
  定数sameHandle = handleList.find(
    (item) => item.url === url && JSON.stringify(item.requestObj) === JSON.stringify(requestObj)
  )
  if (同じハンドル) {
    // 同じリクエストに遭遇した場合、前のリクエストのプロミスが直接返されます
    console.log(`重複したリクエストがあります。直接返します`)
    sameHandle.handleを返す
  }
  const ハンドル = 新しい Promise((resolve, 拒否) => {
    httpリクエスト()
      .then((res) => {
        解決する
      })
      .catch((エラー) => {
        拒否(エラー)
      })
      .finally(() => {
        // リクエストの結果に関係なく、対応するリクエストを削除する必要があります handleList = handleList.filter(
              (アイテム) =>
                item.url !== url && JSON.stringify(item.requestObj) !== JSON.stringify(requestObj)
            )
      })
  })
  handleList.push({ url, requestObj, handle })
  リターンハンドル
}

// ******************************** ゴージャスな分割線を使い始めています ********************************
定数パラメータ = {
  名前: 'ウォルドン'
}
リクエストテスト('/ajax/sameUrl', パラメータ).then((res) => {
  console.log(`最初のリクエスト結果`, res)
  console.log(`ハンドルリスト:`, ハンドルリスト)
})
リクエストテスト('/ajax/sameUrl', パラメータ).then((res) => {
  console.log(`繰り返しリクエスト結果`, res)
  console.log(`handleList:`, handleList) // リクエストリストには常に 1 つのリクエストのみが含まれます setTimeout(() => {
    console.log(`リクエスト完了後のhandleList:`, handleList) // リクエストが完了すると、handleListに対応するリクエストがクリアされます}, 100)
})
タイムアウトを設定する(() => {
  // インターフェースを 1 秒後に返すように設定したので、リクエストを 500 ミリ秒遅らせます。同じ結果が得られるはずです。requestTest('/ajax/sameUrl', params).then((res) => {
    console.log(`繰り返しリクエスト結果`, res)
    console.log(`ハンドルリスト:`, ハンドルリスト)
  })
}, 500)

出力

重複したリクエストがある場合は直接戻ります 重複したリクエストがある場合は直接戻ります 最初のリクエストの結果は成功で、タイムスタンプは次のようになります: 1621650375540
ハンドルリスト:[
{
URL: '/ajax/sameUrl',
リクエストオブジェクト: { 名前: 'waldon' },
ハンドル: Promise { 'リクエストは成功しました、タイムスタンプ: 1621650375540' }
}
]
リクエストを繰り返すと、リクエストは成功します。タイムスタンプは 1621650375540 です。
ハンドルリスト:[
{
URL: '/ajax/sameUrl',
リクエストオブジェクト: { 名前: 'waldon' },
ハンドル: Promise { 'リクエストは成功しました、タイムスタンプ: 1621650375540' }
}
]
リクエストを繰り返すと、リクエストは成功します。タイムスタンプは 1621650375540 です。
ハンドルリスト:[
{
URL: '/ajax/sameUrl',
リクエストオブジェクト: { 名前: 'waldon' },
ハンドル: Promise { 'リクエストは成功しました、タイムスタンプ: 1621650375540' }
}
]
リクエストが完了した後のhandleList: []

コードアドレス codepen

https://codepen.io/waldonUB/pen/ZEeeONM

注意すべき点

  • 応答にデータを追加または削除しないでください。繰り返しのリクエストによって返される Promise 内のオブジェクト参照アドレスは同じであるため、変更するとデータ汚染が発生します。特別な場合には、応答結果を浅くコピーして処理したり、対応するアサーションを追加したりできます。
  • 繰り返しのリクエストを処理するときは、他のユーザーが間違いを犯さないように、ログにプロンプ​​トを表示し、コンポーネントに理由と使用シナリオを注釈付けするのが最適です。
  • 極端なケースでのリクエストの失敗に対処できるように準備し、リクエスト情報をクリアして削除するための有効な時間を設定し、クロージャに蓄積された無駄なリクエスト情報が多すぎることによるメモリ リークを回避します。

JavaScript で promise を使用して複数の繰り返しリクエストを処理する方法については、これで終わりです。js promise の複数の繰り返しリクエストの詳細については、123WORDPRESS.COM の以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • JavaScript 非同期プログラミングにおける Promise の初期の使用法の詳細な説明
  • node.js Promiseオブジェクトの使用例の分析
  • WeChatアプレットJSスクリプトでPromiseを使用して関数処理を最適化する方法の詳細な説明
  • jsはPromiseを使用してシンプルなAjaxキャッシュを実装します
  • JS で Promise を使用して信号機のサンプル コードを実装する (デモ)
  • JavaScript における Promise の使用に関する詳細な説明
  • JavaScript での Promise の使用法の詳細な説明

<<:  Linux でディスクをマウントし、起動時に自動的にマウントするように設定する方法

>>:  Mysql テーブルで利用可能な最小 ID 値を照会する方法

推薦する

Linux ログ表示方法 6 つのまとめ

バックエンド プログラマーは、さまざまな場所で Linux を扱います。Linux ログの読み方がわ...

Reactはconetxtを通じてマルチコンポーネント値転送関数を実装します

この関数の効果はvue的provide/injectに似ています。 contextを通じて反応できる...

Vue で Excel ストリーム ファイルをダウンロードし、ダウンロード ファイル名を設定する方法

目次概要1. URL経由でダウンロード2. aタグのダウンロード属性とblobコンストラクタを組み合...

DockerはホストのMysql操作に接続します

今日、会社のプロジェクトでは docker を設定する必要があります。Windows に正常にインス...

Vueフォームで画像を処理する方法

質問: Vue にブログ投稿をアップロードするためのフォームがあり、タイトル、本文、説明、スニペット...

uniapp エントリーレベル nvue クライミングピット記録の分析

目次序文こんにちは世界画像 境界線の半径を設定する実ピクセルを設定する外部CSSをインポートttfフ...

Dockerコンテナを外部IPとポートにバインドする方法

Docker を使用すると、外部からコンテナにアクセスしたり、コンテナを相互接続したりすることで、ネ...

TypeScript で時間を費やした場所の概要

TS で時間を過ごした場所をいくつか記録します。 (まず、文句を言わせてください。stackover...

MySQL インデックスのクイックガイド

MySQL インデックスの確立は、MySQL の効率的な操作にとって非常に重要です。インデックスによ...

startup.bat をダブルクリックすると Tomcat がクラッシュする問題の解決方法の詳細な説明

Tomcat を学習したばかりのプログラマーにとって、これはよくある間違いです。 1. 環境変数の問...

Docker のタイムゾーンの問題とデータ移行の問題

最新のソリューション: -v /usr/share/zoneinfo/Asia/Shanghai:/...

sbinディレクトリを生成せずにNginxをインストールするソリューション

エラーの説明: 1. Linux (CentOS 7 64) システムに Nginx (1.18.0...

Win10 構成 Tomcat 環境変数チュートリアル図

設定する前に、次の操作を行う必要があります。 1. まずjdk bloggerをインストールします。...

win10にUbuntu18デュアルシステムをインストールするとmmx64.efiが見つからないという問題が発生する

Ubuntu 18のインストール中に、USBディスクからUbuntuのインストールを開始すると、mm...

MySQLが大量のデータを処理する際にクエリ速度を最適化するいくつかの方法

実際に参加したプロジェクトでは、MySQL テーブルのデータ量が数百万に達すると、通常の SQL ク...