この記事では、Nodejs 開発プロセスで遭遇する配列の特性によって発生する問題と解決策、および配列の柔軟な適用について主に記録します。 この記事のテスト結果はノードv6.9.5に基づいています。 配列とキュー配列オブジェクトの push/shift メソッドを使用して、キューの先入れ先出し機能を実装できます。次に例を示します。 >a=[] [] >a.push(2.3.4) 3 >a.プッシュ(2) 3 >あ [2.3.4.2] >a.シフト() 2 >あ >[3.4.2] 配列と forEach配列を削除する一般的な方法は、delete と splice メソッドを使用する 2 つあります。これらの違いを明確にする必要があります。
配列から要素を完全に削除したい場合は、splice を使用します。 > a=[1,2,3] [ 1, 2, 3 ] > a.スプライス(1,1) [ 2 ] > 1つの [ 1, 3 ] > a.長さ 2 > a.forEach(function(item, index){console.info("index[", index,"]:", item)}); インデックス[0]:1 インデックス[ 1 ]: 3 未定義 > では、delete を使用して要素オブジェクトを削除した後に forEach を実行するとどのような効果があるのでしょうか? 空要素を含む配列に対する forEach の処理メカニズムテスト結果は次のとおりです > a=[1,2,3] [ 1, 2, 3 ] > [1]を削除 真実 > 1つの [ 1, 3 ] > a.長さ 3 > a.forEach(function(item, index){console.info("index[", index,"]:", item)}); インデックス[0]:1 インデックス[ 2 ]: 3 未定義 テスト結果から、forEach は値が未定義の項目を走査しないことがわかります。実際のアプリケーションでは、forEach が終了したかどうかを判断することが大きな課題となります。 forEach の非同期機能の適用を解決するには、配列にプロトタイプを追加して、有効なデータを自分で管理および設定します。 効果は以下のとおりです。 > a=[1,2,3] [ 1, 2, 3 ] > a.有効数=3 3 > 削除[2] 真実 > a.有効数=2 2 > 1つの [ 1, 2, , 有効数字: 2 ] > a.長さ 3 > 有効数字 2 > a.forEach(function(item, index){console.info("index[", index,"]:", item)}); インデックス[0]:1 インデックス[ 1 ]: 2 未定義 > 補足: Node.jsの配列forEachはコンテキストステートメントを同期的に処理します 私は C 言語の考え方に慣れており、初めて Node.js に触れたときは、その非同期処理に頭を悩ませました。 コードを記述するときに、配列内の要素をループで処理し、すべての処理が完了した後に最後の操作を実行する必要があるシナリオに遭遇することがあります。ただし、JS の非同期の性質により、この最後のステートメントが最初に実行されるため、forEach について学習する時間を取ってください。 口先だけではダメ。コードを見せてください。 forEach の使用法forEach は配列構造をトラバースするために使用されます。誰かが forEach は最下層で for を使用して実装されていると言っていました。詳しくは調べていませんが、少なくとも効果は同じであるようです。 forEach のコールバック関数の 3 つのパラメーターは、値、シーケンス番号、元の配列です。シーケンス番号は0から始まります。 (() => { arr = [2, 3, 1]とします。 arr.forEach(関数 (値, インデックス, 配列) { console.log(値); コンソールログ(インデックス); console.log(配列); コンソールログ('-----'); }); })(); 出力 2 0 [ 2, 3, 1 ] ----- 3 1 [ 2, 3, 1 ] ----- 1 2 [ 2, 3, 1 ] ----- 結果から、forEach の複数のループが同期されている、つまり順番に実行されていることがわかります。しかし、JS であることを考えると、同期は不可能な気がします。 。確認できます。 forEachは複数のループを非同期的に処理します今回は、forEach にタイマー タスクを追加し、各ループ操作を値に関連する時間だけ遅延させて、より時間のかかる操作をシミュレートします。 (() => { arr = [2, 3, 1]とします。 arr.forEach(関数 (値, インデックス, 配列) { setTimeout(関数() { console.log(値); }, 値*100); }); })(); 出力 1 2 3 結果から、最も時間の短いタスクが最初に完了し、各ループのタスクがループの順序どおりに実行されず、つまり複数のループが非同期で処理されていることがわかります。 forEachコンテキストも非同期に実行される冒頭で述べた問題に戻ると、複数のループが順番に実行されるかどうかに関係なく、forEach 内のすべてのタスクが完了した後にデータの一部を実行して、すべてのタスクが完了したことを通知する必要があります。 (() => { arr = [2, 3, 1]とします。 arr.forEach(関数 (値, インデックス, 配列) { setTimeout(関数() { console.log(値); }, 値*100); }); console.log('すべての作業が完了しました'); })(); 出力 すべての作業は完了しました 1 2 3 結果から、コンテキスト ステートメントも同期されていないことがわかります。forEach ループ内のタスクは、すべてのタスクが完了したことを通知する前に完了しません。これは明らかに期待どおりではありません。 この問題について多くのブログを読みましたが、適切な解決策を見つけることができませんでした。最終的に、Promise.all を使用してこの機能をかろうじて実装することしかできませんでした。 Promise.allはforEachコンテキストステートメントの同期処理を実装します。上記のコードを Promise.all 構造に変更します。各ループの最後に、resolve() が呼び出されます。Promise.all の then 関数は、すべての Promise が実行されたときにのみトリガーされることがわかっており、これはニーズを満たしているようです。 (() => { arr = [2, 3, 1]とします。 proArr = [] とします。 arr.forEach(関数(値、インデックス) { proArr[インデックス] = 新しいPromise(関数(解決) { setTimeout(関数() { console.log(値); 解決する(); }, 値*100); }); }); Promise.all(proArr).then(()=>{ console.log('すべての作業が完了しました'); }) })(); 出力 1 2 3 すべての作業は完了しました 結果から判断すると、私たちのニーズは満たされました。 起こりうる問題JS の非同期特性を考えてみると、この方法には問題があるかもしれないと突然気づきました。 ここでは、forEach に入るたびに Promise 配列が割り当てられます。この操作時間は非常に短いはずです。最後の Promise.all ステートメントは、3 つのループで割り当てが完了した後にのみ呼び出されます。 ただし、配列が非常に大きく、ループ割り当て操作に非常に時間がかかる場合、割り当て操作の半分しか完了していないと、最後の Promise.all の実行時に渡される Promise 配列は、すべての Promise を含む配列ではない可能性があります。 この場合、Promise.all は半分の操作だけを待機します。Promise.all が待機しているとき、配列の後ろに割り当てられた Promise が待機されるかどうかは不明です。 私は JS を使い始めたばかりで、実装の仕組みを理解していないため、この問題が存在するかどうかを確認するために実験することしかできません。次に、この配列を大きくしてみましょう。配列を大きくするために最も確実な方法を使用していることをお許しください。 (() => { arr = [2, 3, 1, 2, 3, 1, 2, 3, 1, 2]; // 10 arr = arr.concat(arr); // 2^1 * 10 arr = arr.concat(arr); // 2^2 * 10 arr = arr.concat(arr); // 2^3 arr = arr.concat(arr); // 2^4 arr = arr.concat(arr); // 2^5 arr = arr.concat(arr); arr = arr.concat(arr); arr = arr.concat(arr); arr = arr.concat(arr); arr = arr.concat(arr); // 2^10 arr = arr.concat(arr); arr = arr.concat(arr); arr = arr.concat(arr); arr = arr.concat(arr); arr = arr.concat(arr); // 2^15 arr = arr.concat(arr); arr = arr.concat(arr); // 2^17 * 10 // arr = arr.concat(arr); // 2^18 * 10 console.log(arr.length); proArr = [] とします。 arr.forEach(関数(値、インデックス) { proArr[インデックス] = 新しいPromise(関数(解決) { setTimeout(関数() { console.log(値); 解決する(); }, 値*100); }); }); Promise.all(proArr).then(()=>{ console.log('すべての作業が完了しました'); console.log(arr.length); }).catch(関数(エラー) { コンソールログ(エラー); }) })(); 私のコンピューターでテストしたところ、配列の長さが 2^18 * 10 の場合、Promise はエラー RangeError: Too many elements provided to Promise.all を報告します。 配列の長さが 2^17 * 10、つまり 2621440 の場合、正常に実行されます。何度かテストした結果、最後に実行されたコマンド出力「All the work is done」が常に最後に出力されます (ターミナル バッファーが小さすぎるため、出力結果は node xx.js > log.txt リダイレクトを使用して表示用にファイルにリダイレクトされます)。 もちろん、アプリケーションにはそれほど大きな配列はありません。結果から判断すると、実際のアプリケーションでは上記の問題は存在しません。 つまり、Promise.all は forEach コンテキスト ステートメントの同期処理を実装するために使用できます。 上記は私の個人的な経験です。参考になれば幸いです。また、123WORDPRESS.COM を応援していただければ幸いです。間違いや不備な点がありましたら、遠慮なくご指摘ください。 以下もご興味があるかもしれません:
|
>>: Ansible を使用した Nginx のバッチ デプロイのサンプル コード
目次序文Zookeeper サービスのオープンを検出情報を入手する接続テスト接続先修理計画参照する序...
最近、CSS3 アニメーションのソース コードの実装をいくつか見ていたところ、CSS コード アニメ...
序文実稼働環境で Docker を使用する場合、多くの場合、データを複数のコンテナ間で永続化または共...
序文:インターネット技術の継続的な発展に伴い、MySQL 関連のエコシステムはますます充実し、ますま...
まず、VMware 14のアクティベーションコードをお渡ししますFF31K-AHZD1-H8ETZ-...
Ansible は、Python をベースに開発された新しい自動運用・保守ツールです。 多くの古い運...
過去 N 秒間の QPS 値の統計 (1 秒あたりの選択、挿入などを含む) mysql> se...
MySQL では、REVOKE ステートメントを使用してユーザーの特定の権限を削除できます (ユーザ...
序文コードを書く過程で、必然的にコードに何らかの変更を加えることになります。しかし、変更を加えるとき...
RPM パッケージ管理インターネット ダウンロード パッケージのパッケージ化およびインストール ツー...
Msyqlデータベースのインストール、参考までに具体的な内容は次のとおりです。 ①ブラウザでhttp...
この記事では、MySQL の整合性制約について説明します。ご参考までに、詳細は以下の通りです。メイン...
Element-UI に慣れた開発者なら、無限スクロールの InfiniteScroll が使いにく...
springboot には tomcat サーバーが組み込まれているため、jar パッケージにパッケ...
目次1. 説明2. インストール3. テスト1. 説明Vue Router は、Vue.js の公式...