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 値を照会する方法

推薦する

シンプルなドラッグ効果を実現するJavaScript

この記事では、簡単なドラッグ効果を実現するためのJavaScriptの具体的なコードを参考までに紹介...

Vue ページ印刷で自動ページングを実装する 2 つの方法

この記事では、ページ印刷の自動ページングを実現するためのVueの具体的なコードを例として紹介します。...

フロントエンドは画像を遅延ロードする方法を知っている必要があります(3つの方法)

目次1. 遅延読み込みとは何ですか? 2. 遅延読み込みを実装する🌄: 2.1 最初の方法: 2.2...

CSSスコープ(スタイル分割)の使用の概要

1. CSSスコープの使用(スタイル分割) Vue では、CSS スタイルを現在のコンポーネントでの...

Linux でディスク IO を表示し、読み取りと書き込みで高い IO を占有するプロセスを見つけます。

背景 - オンラインアラートオンライン サーバーがアラームを発し、ディスク使用率 disk.util...

DOCTYPE HTMLを使用する理由

これがないと、ブラウザはページをレンダリングするときに Quirks モードを使用することがわかって...

Bash スクリプトでの配列メソッドの作成と使用の概要

Bashで配列を定義するbash スクリプトで新しい配列を作成する方法は 2 つあります。 1 つ目...

mysql8でルートユーザーのパスワードをリセットする手順を完了します

序文最近、多くの新しい同僚がこの質問をしてきました。特に、homebrew を通じて自動的にインスト...

AES_ENCRYPT() と AES_DECRYPT() を使用して MySQL を暗号化および復号化する正しい方法の例

序文最近、仕事でAES_ENCRYPT()関数を使用してプレーンテキストを暗号化し、MySQL に保...

WebデザイナーがRetinaディスプレイデバイス向けの画像を作成する方法

特記事項:この記事は、Chris Spooner の英語記事「Web デザイン用の Retina グ...

jsはテーブルドラッグオプションを実装します

この記事の例では、テーブルドラッグオプションを実装するためのjsの具体的なコードを参考までに共有して...

初心者のためのWebページ作成: HTMLのハイパーリンクAタグの使い方を学ぶ

ハイパーリンク a タグはリンク ポイントを表し、英語の単語「anchor」の略語です。その機能は、...

CentOS7.5にHarbor1.7をインストールして設定するプロセス全体

1. 必要なパッケージをダウンロードする wget -P /usr/local https://st...

トップに戻るボタンを実装するJavaScript

この記事では、トップに戻るボタンを実装するためのJavaScriptの具体的なコードを参考までに紹介...

Kubernetesでポッドを作成する方法

目次ポッドを作成するには? kubectl ツールポッドを作成するには?前回の記事では、コンテナとポ...