一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服務器之家 - 編程語言 - JavaScript - node.js - Nodejs 數組的隊列以及forEach的應用詳解

Nodejs 數組的隊列以及forEach的應用詳解

2022-01-24 16:38WificamSDK7 node.js

這篇文章主要介紹了Nodejs 數組的隊列以及forEach的應用詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧

本文主要記錄了在Nodejs開發過程中遇到過的由數組特性引起的問題及解決方式,以及對數組的靈活應用。

本文代碼測試結果均基于node v6.9.5

數組與隊列

利用數組對象方法push/shift可實現隊列先進先出特性,例如:

?
1
2
3
4
5
6
7
8
9
10
11
12
>a=[]
[]
>a.push(2.3.4)
3
>a.push(2)
3
>a
[2.3.4.2]
>a.shift()
2
>a
>[3.4.2]

數組與forEach

對數組的刪除操作有兩種常見方式:delete和使用splice方法,需要明確他們的區別。

操作/方法 說明
splice 刪除并返回指定的數組元素,數組本身長度會改變;但不會free元素對象
delete 刪除(free)元素對象,數組元素不變,值變為undefined

如果要從數組中徹底刪除某個元素,使用splice即可:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
> a=[1,2,3]
[ 1, 2, 3 ]
> a.splice(1,1)
[ 2 ]
> a
[ 1, 3 ]
> a.length
2
> a.forEach(function(item, index){console.info("index[", index,"]:", item)});
index[ 0 ]: 1
index[ 1 ]: 3
undefined
>

那么,當使用delete刪除某個元素對象后,此時執行forEach的效果是什么?

forEach對含空元素數組處理機制

測試結果如下

?
1
2
3
4
5
6
7
8
9
10
11
12
> a=[1,2,3]
[ 1, 2, 3 ]
> delete a[1]
true
> a
[ 1, , 3 ]
> a.length
3
> a.forEach(function(item, index){console.info("index[", index,"]:", item)});
index[ 0 ]: 1
index[ 2 ]: 3
undefined

從測試結果來看,forEach并不會遍歷到值為undefined的哪一項。這在實際應用中如何判斷forEach是否結束是一大挑戰。

解決配合forEach的異步特性應用,可為數組添加prototype來自行管理設置有效數據;

效果如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
> a=[1,2,3]
[ 1, 2, 3 ]
> a.validnum=3
3
> delete a[2]
true
> a.validnum=2
2
> a
[ 1, 2, , validnum: 2 ]
> a.length
3
> a.validnum
2
> a.forEach(function(item, index){console.info("index[", index,"]:", item)});
index[ 0 ]: 1
index[ 1 ]: 2
undefined
>

補充:Node.js 數組 forEach 同步處理上下文語句

習慣了C語言系的思維方式,剛接觸Node.js,它的異步處理讓我頭大。

寫代碼遇到這么一個場景,需要循環對一個數組中的元素進行處理,全部處理完成后再執行一個last操作。但是JS的異步特性會使這個last語句先執行,所以花點時間研究研究forEach。

Talk is cheap. Show me the code.

forEach 用法

forEach用于對數組結構進行遍歷,看到有人說forEach底層是用for實現的,沒深究,起碼效果上看是一樣的。forEach的回調函數3個參數分別是:值、序號和原數組。序號從0開始。

?
1
2
3
4
5
6
7
8
9
(() => {
  let arr = [2, 3, 1];
  arr.forEach(function (value, index, array) {
    console.log(value);
    console.log(index);
    console.log(array);
    console.log('-----');
  });
})();

Output

?
1
2
3
4
5
6
7
8
9
10
11
12
2
0
[ 2, 3, 1 ]
-----
3
1
[ 2, 3, 1 ]
-----
1
2
[ 2, 3, 1 ]
-----

從結果上看forEach多次循環之間是同步的,也就是說都是按順序執行的。但是一想到它是JS就感覺不可能同步的。。可以驗證一下。

forEach 異步處理多次循環

這次在forEach加個定時任務,每次循環操作都延時value相關的時間,模擬比較耗時的操作。

?
1
2
3
4
5
6
7
8
(() => {
  let arr = [2, 3, 1];
  arr.forEach(function (value, index, array) {
    setTimeout(function () {
      console.log(value);
    }, value*100);
  });
})();

Output

?
1
2
3
1
2
3

從結果可以看出耗時最短的任務先完成,每次循環的任務并不是按循環的先后順序執行的,也就是說異步處理多次循環。

forEach 上下文也是異步執行

回到開始說到的問題了,且不管多次循環是不是按順序執行,我需要forEach中的所有任務都完成后執行一條數據來通知我任務全部完成了。

?
1
2
3
4
5
6
7
8
9
(() => {
  let arr = [2, 3, 1];
  arr.forEach(function (value, index, array) {
    setTimeout(function () {
      console.log(value);
    }, value*100);
  });
  console.log('All the work is done');
})();

Output

?
1
2
3
4
All the work is done
1
2
3

從結果來看,上下文的語句也不是同步的,forEach循環中的任務沒有完成就通知所有任務都完成了,顯然不符合預期。

針對這個問題看了好多個博客,都沒有找到合適的解決方法,最后只能想到用Promise.all來勉強實現這個功能。

Promise.all 實現 forEach 上下文語句同步處理

把上面的代碼改成Promise.all的結構。每個循環中執行結束調用resolve(),我們知道Promise.all的then函數,只有所有的Promise都執行完成才會觸發,這樣好像能滿足我們的需求。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(() => {
  let arr = [2, 3, 1];
  let proArr = [];
  arr.forEach(function (value, index) {
    proArr[index] = new Promise(function (resolve) {
      setTimeout(function () {
        console.log(value);
        resolve();
      }, value*100);
    });
  });
  Promise.all(proArr).then(()=>{
    console.log('All the work is done');
  })
})();

Output

?
1
2
3
4
1
2
3
All the work is done

從結果來看,滿足了我們的需求。

可能還存在的問題

想到JS異步特性,突然發現可能這個方法還存在個問題。

這里每次 forEach 剛進入就對 Promise 數組進行了賦值操作,這個操作時間應該非常短,循環3次都賦值完成后才調用最后的Promise.all語句。

但是如果這個數組非常大,這個循環賦值的操作非常耗時間的話,假如只完成了一半的賦值操作,那么執行最后這個 Promise.all 的時候傳入的 Promise 數組可能并不是包含所有 Promise 的數組。

這樣的話 Promise.all 等待的就只有一半的操作,Promise.all 等待的時候,這個數組后面被賦值的 Promise 不知道會不會被等待。

剛接觸JS不明白實現機制,只能實驗來驗證一下是否存在這個問題。接下來用把這個數組弄大一些,請原諒我用最傻瓜式的方式搞大它。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
(() => {
  let 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);
  let proArr = [];
  arr.forEach(function (value, index) {
    proArr[index] = new Promise(function (resolve) {
      setTimeout(function () {
        console.log(value);
        resolve();
      }, value*100);
    });
  });
  Promise.all(proArr).then(()=>{
    console.log('All the work is done');
    console.log(arr.length);
  }).catch(function (err) {
    console.log(err);
  })
})();

經過測試在我這個電腦上當數組長度為2^18 * 10的時候,Promise報錯 RangeError: Too many elements passed to Promise.all。

當數組長度為2^17 * 10 即2621440的時候,會正常運行。測試了幾次,最后的執行命令輸出的All the work is done始終在最后輸出(因為終端緩沖區太小,所以使用node xx.js > log.txt重定向的方式把輸出結果重定向到文件查看)。

當然應用中也不會有這么大的數組,從結果看的話,就是實際應用中不存在上面考慮可能出現的問題。

也就是說可以用 Promise.all 實現 forEach 上下文語句同步處理。

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持服務器之家。如有錯誤或未考慮完全的地方,望不吝賜教。

原文鏈接:https://blog.csdn.net/WificamSDK7/article/details/78460408

延伸 · 閱讀

精彩推薦
  • node.jsrequire加載器實現原理的深入理解

    require加載器實現原理的深入理解

    這篇文章主要給大家介紹了關于require加載器實現原理的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需...

    隱冬8462022-03-03
  • node.jsnodejs中使用worker_threads來創建新的線程的方法

    nodejs中使用worker_threads來創建新的線程的方法

    這篇文章主要介紹了nodejs中使用worker_threads來創建新的線程的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友...

    flydean程序那些事8982022-01-06
  • node.js在瀏覽器中,把 Vite 跑起來了!

    在瀏覽器中,把 Vite 跑起來了!

    大家好,我是 ssh,前幾天在推上沖浪的時候,看到 Francois Valdy 宣布他制作了 browser-vite[1],成功把 Vite 成功在瀏覽器中運行起來了。這引起了我的興趣,如...

    前端從進階到入院9282022-01-11
  • node.js詳解node.js創建一個web服務器(Server)的詳細步驟

    詳解node.js創建一個web服務器(Server)的詳細步驟

    這篇文章主要介紹了詳解node.js創建一個web服務器(Server)的詳細步驟,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,...

    王佳斌8952021-12-31
  • node.jslinux服務器快速卸載安裝node環境(簡單上手)

    linux服務器快速卸載安裝node環境(簡單上手)

    這篇文章主要介紹了linux服務器快速卸載安裝node環境(簡單上手),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需...

    mose-x8462022-01-22
  • node.jsNode.js ObjectWrap 的弱引用問題

    Node.js ObjectWrap 的弱引用問題

    最近在寫 Node.js Addon 的過程中,遇到了一個問題,然后發現是 ObjectWrap 弱引用導致的,本文介紹一下具體的問題和排查過程,以及 ObjectWrap 的使用問題。...

    編程雜技9852022-01-04
  • node.jsNode.js 中如何收集和解析命令行參數

    Node.js 中如何收集和解析命令行參數

    這篇文章主要介紹了Node.js 中如何收集和解析命令行參數,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋...

    descire8802021-12-28
  • node.jsk8s node節點重新加入master集群的實現

    k8s node節點重新加入master集群的實現

    這篇文章主要介紹了k8s node節點重新加入master集群的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋...

    Scarborought13922022-01-22
主站蜘蛛池模板: 糖心视频在线观看 | 国产激情久久久久影院小草 | 99精品久久99久久久久久 | 小泽玛丽av无码观看 | 久久综合狠狠综合久久综合88 | 婚前试爱免费看 | 免费国产一级 | 国产新疆成人a一片在线观看 | 国产一卡二卡四卡免费 | 校园春色自拍偷拍 | 毛片应用 | 久久精品亚洲国产AV涩情 | 五月香婷婷 | 深夜福利在线播放 | 污漫日本E同人 | 好大好硬好长好爽a网站 | 好硬好大好浪夹得好紧h | 日本高清视频一区二区 | 国内亚州视频在线观看 | 农村妇女野外性生话免费视频 | 免费网站看v片在线成人国产系列 | 免费看一区二区三区 | 日本精品一二三区 | 国产农村一级特黄α真人毛片 | 日韩在线免费 | 亚洲一级特黄特黄的大片 | 色戒完整版 | 韩国伊人 | zoz.zzz色| 国内精品 大秀视频 日韩精品 | 古代色翁荡熄 | 狠狠干2016 | www.四虎.com| 和两个男人玩3p好爽视频 | juliaann大战黑人 | 九九精品国产 | 四虎影院最新网址 | 国产第一福利 | 高清不卡一区 | 国产高清在线播放免费观看 | 国产毛片一级aaaaa片 |