Promise.all的深入理解

異步之Promise

Promise.all

Promise.all接收的promise數組是按順序執行的還是一起執行的,也就是說返回的結果是順序固定的嗎?

目前有兩種答案:

  1. 應該是同步執行的,但是這樣就有效率問題了,如果想改成異步執行怎么辦呢?
  2. 有些人認為結果是按順序執行的,有些人認為結果順序不確定。

那么我們根據實現來解密:

環境為:

vscode 1.20.1
node   v8.9.0
npm    v5.6.0

實驗代碼:

// 獲取隨機數,toFixed為四舍五入保留小數,0為保留整數,范圍~1000
const getRandom = () => +(Math.random()*1000).toFixed(0);const asyncTask = (taskID) => new Promise( (resolve) => {// 隨機獲取一次0~1000的隨機數let timeout = getRandom();// 打印出傳遞進來的ID號 taskID=1 start.console.log(`taskID=${taskID} start.`);// 設置計時時間,function()等價于 () => {...}setTimeout(function() {// 打印出執行的taskID,和timeoutconsole.log(`taskID=${taskID} finished in time=${timeout}.`);// 異步成功執行resolve(taskID)}, timeout);
});Promise.all([asyncTask(1),asyncTask(2),asyncTask(3)])
.then(resultList => {console.log('results:',resultList);
});

實驗結果如下:

第一次

taskID=1 start.
taskID=2 start.
taskID=3 start.
taskID=2 finished in time=321.
taskID=3 finished in time=506.
taskID=1 finished in time=932.
results:
Array(3) [1, 2, 3]

第二次

taskID=1 start.
taskID=2 start.
taskID=3 start.
taskID=1 finished in time=243.
taskID=3 finished in time=305.
taskID=2 finished in time=792.
results:
Array(3) [1, 2, 3]

第三次

taskID=1 start.
taskID=2 start.
taskID=3 start.
taskID=3 finished in time=380.
taskID=1 finished in time=539.
taskID=2 finished in time=782.
results:
Array(3) [1, 2, 3]

補充知識介紹

// toFixed() 方法可把 Number 四舍五入為指定小數位數的數字。
NumberObject.toFixed(num)
// num	必需。規定小數的位數,是 0 ~ 20 之間的值,包括 0 和  
// 20,有些實現可以支持更大的數值范圍。如果省略了該參數,將用 0 代替。

Promise構造函數只有一個參數,該參數是一個函數,被稱作執行器,執行器有2個參數,分別是resolve()和reject(),一個表示成功的回調,一個表示失敗的回調。

new Promise(function(resolve, reject) {setTimeout(() => resolve(5), 0)
}).then(v => console.log(v)) // 5

記住,Promise實例只能通過resolve或者reject函數來返回,并且使用then()或者catch()獲取,不能在new Promise里面直接return,這樣是獲取不到Promise返回值的。


由此可見,Promise.all 里的任務列表[asyncTask(1),asyncTask(2),asyncTask(3)],我們是按照順序發起的。
但是根據結果來說,它們是異步的,互相之間并不阻塞,每個任務完成時機是不確定的,盡管如此,所有任務結束之
后,它們的結果仍然是按順序地映射到resultList里,這樣就能和Promise.all里的任務列表
[asyncTask(1),asyncTask(2),asyncTask(3)]一一對應起來。

深入理解Promise.all()

*可能看到這里有些人沒有清楚,為什么返回一個數組? *
我們在來看一下這段代碼:

Promise.all([asyncTask(1),asyncTask(2),asyncTask(3)])
.then(resultList => {console.log('results:',resultList);
});

通常我們在使用異步的時候都是只有一個Promise,現在我們使用all()方法包裝多個Promise實例。

語法很簡單:參數只有一個,可迭代對象,可以是數組,或者Symbol類型等。

Promise.all(iterable).then().catch()

傳入3個Promise實例:

Promise.all([new Promise(function(resolve, reject) {resolve(1)}),new Promise(function(resolve, reject) {resolve(2)}),new Promise(function(resolve, reject) {resolve(3)})
]).then(arr => {console.log(arr) // [1, 2, 3]
})

那么我們回頭想想應該明白了吧?
因為我們傳入的是數組,那么返回的必須是數組,并且會將講過進行映射。

Promise.race()

語法和all()一樣,但是返回值有所不同,race根據傳入的多個Promise實例,只要有一個實例resolve或者reject,就只返回該結果,其他實例不再執行。

我們簡單看一下例子,返回結果為3,因為我們設置了定時器,第三個Promise執行的最快。

Promise.race([new Promise(function(resolve, reject) {setTimeout(() => resolve(1), 1000)}),new Promise(function(resolve, reject) {setTimeout(() => resolve(2), 100)}),new Promise(function(resolve, reject) {setTimeout(() => resolve(3), 10)})
]).then(value => {console.log(value) // 3
})

異步為什么使用箭頭函數

這是我一直困惑的原因,我們將前面的例子進行改造一下。

如下:

const getRandom = () => +(Math.random()*1000).toFixed(0);function test(taskID) {return new Promise( (resolve) => {// 隨機獲取一次0~1000的隨機數let timeout = getRandom();// 打印出傳遞進來的ID號console.log(`taskID=${taskID} start.`);setTimeout(function() {console.log(`taskID=${taskID} finished in time=${timeout}.`);resolve(taskID)}, timeout);
} )
}Promise.all([test(1),test(2),test(3)])
.then(resultList => {console.log('results:',resultList);
});

我們先來看一下結果是怎樣的?

第一次:

taskID=1 start.
taskID=2 start.
taskID=3 start.
results:
Array(3) [undefined, undefined, undefined]
taskID=1 finished in time=460.
taskID=2 finished in time=704.
taskID=3 finished in time=883.

第二次:

taskID=1 start.
taskID=2 start.
taskID=3 start.
results:
Array(3) [undefined, undefined, undefined]
taskID=2 finished in time=17.
taskID=3 finished in time=212.
taskID=1 finished in time=612.

第三次:

taskID=1 start.
taskID=2 start.
taskID=3 start.
results:
Array(3) [undefined, undefined, undefined]
taskID=3 finished in time=130.
taskID=1 finished in time=256.
taskID=2 finished in time=593.

實驗還是要至少做上3次以上才有說服力。

通過輸出結果我們能夠看出返回的數組內的數據都為undefined。我們就要找出這個原因,那就是找到了為什么要使用箭頭函數。

  1. 首先我通過調試來查找
    如圖:
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-oZTdOow8-1628238283115)(https://note.youdao.com/yws/api/personal/file/WEBcfbe51c67215e9414c1ac940d99e0caa?method=download&shareKey=c3945e0b4a991911953e4986d51b11cd)]

程序首先打印出了

taskID=1 start.
taskID=2 start.
taskID=3 start.

說明一定是先執行了

console.log(`taskID=${taskID} start.`);

所以我們在這段打上斷點進行一步一步調試,如下:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-vVqeaAeA-1628238283117)(https://note.youdao.com/yws/api/personal/file/WEBdae375d2f798007f6390ff75f746943b?method=download&shareKey=3c091febde5a6b7e582e7a261b7b8854)]

根據上圖我們可以看出console.log(taskID=${taskID} start.)每次都會被執行,setTimeout也會被執行,但是3次之后,就會直接開始執行.then(),所以我們找到了原因,Promise.all()這時并沒有等待返回完整的數據就執行了.then(),沒有等到resolve就開始執行了。

說明這里面出現了異常,而這個異常就是由于Promise.all()內的參數,存在函數,造成this混淆,所以我們要使用對象,更準確的說法就是***實例***。

注意:

以這段代碼為例:

var p1 = Promise.resolve(1),p2 = Promise.resolve(2),p3 = Promise.resolve(3);
Promise.all([p1, p2, p3]).then(function (results) {console.log(results);  // [1, 2, 3]
});

在上面的方法中,promise數組中所有的promise實例都變為resolve的時候,該方法才會返回,并將所有結果傳遞results數組中。promise數組中任何一個promise為reject的話,則整個Promise.all調用會立即終止,并返回一個reject的新的promise對象。reject使用示例如下:

var p1 = Promise.resolve(1),p2 = Promise.reject(2),p3 = Promise.resolve(3);
Promise.all([p1, p2, p3]).then(function (results) {//then方法不會被執行console.log(results); 
}).catch(function (e){//catch方法將會被執行,輸出結果為:2console.log(2);
});

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/536139.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/536139.shtml
英文地址,請注明出處:http://en.pswp.cn/news/536139.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

wordpress后臺無法登錄問題

之前給自己的WordPress加了個標簽云,今天登錄的時候突然發現網站后臺進不去了,無奈各種找材料,這算是皇天不負有心人,總算是給我找到了,現在做一下記錄 登錄不上的原因在于:wp-admin和wp-admin/是不同的&a…

深入理解Angular訂閱者模式

深入理解Angular訂閱者模式 如果正在讀此篇文章的你學過java,c++等面向對象語言,知道兩個模式觀察者模式和訂閱者模式,分別為:Observer pattern,Pub-sub pattern(Subscriber) 接下來我們結合Angular來說明這兩個模式。 Observer pattern This is a pattern of developme…

Ubuntu中安裝python3

通過命令行安裝Python3.*,只需要在終端中通過命令行安裝即可: sudo apt-get install python3 Ubuntu的底層大多數采用的是Python2.*,Python3和Python2是互相不兼容的,完全沒法通用的(也不知道他們怎么想的o(TヘTo)&a…

Angular深入理解之指令

Angular深入理解之指令 指令有什么功能 Attribute directives 屬性指令Structural directives 結構指令自定義屬性指令自定義結構指令Angular深入理解之指令 對于初學Angular的同學來說,指令無疑是最痛苦的,那么我們怎么使用自定義的指令呢?指令到底怎么實現呢?為什么要寫…

windows下Apache虛擬主機配置

找到host文件:C:\Windows\System32\drivers\etc\hosts 在hosts這么增加: 127.0.0.1 666.666.com 127.0.0.1 777.777.com 修改httpd.conf文件: 打開文件:xxx\xampp\apache\conf\httpd.conf 找到#LoadModule vhost_…

Angular深入理解基本組成

Angular深入理解基本組成 在講指令時,我們先來了解一下Angular的基本概念和結構。 Module 模塊 Angular 是模塊化的.Modules 導出 classes, function, values , 以便在其他模塊導入使用.angular應用由模塊組成,每個模塊都做此模塊相關的事情組件、方法、類、服務等,他們都…

1607: 字符棱形

1607: 字符棱形 根據讀入的字符和邊長,勾畫字符棱形。 Input 輸入數據含有不超過50組的數據,每組數據包括一個可見字符c和一個整數n(1≤n≤30)。 Output 輸出以c為填充字符,邊長為n的棱形,勾畫每個棱形…

Angular深入理解管道Pipe

Angular深入理解管道 純管道與非純管道區別的本質 Pure FunctionImpure Function內置Pipe pipe使用自定義Pipe 管道性能優化Angular深入理解管道 管道的鏈接 有學過linux shell的同學,應該知道管道,在shell中的管道是IPC,linux的進程間通訊有pipe,FIFO,signal。這里只是簡單…

1959: 圖案打印

1959: 圖案打印 Description 一年一度的植樹節就要到了,計算機學院學生準備在學院教學樓門前的空地上種植樹木。為使樹木排列得更加美觀,大家決定把樹木排列成菱形。現在告訴你我們所擁有的樹木能排列成邊長為N的菱形,請你編程輸出樹木所排…

JS事件的捕獲和冒泡階段

JS事件的捕獲和冒泡階段 這里介紹兩個事件模型&#xff1a;IE事件模型與DOM事件模型 IE內核瀏覽器的事件模型是冒泡型事件&#xff08;沒有捕獲事件過程&#xff09;&#xff0c;事件句柄的觸發順序是從ChildNode到ParentNode。 <div id"ancestor"> <butt…

2016: C語言實驗——打印金字塔

2016: C語言實驗——打印金字塔 Description 輸入n值&#xff0c;打印下列形狀的金字塔&#xff0c;其中n代表金字塔的層數。 Input 輸入只有一個正整數n。 Output 打印金字塔圖形&#xff0c;其中每個數字之間有一個空格。 Sample Input 3 Sample Output 11 2 1 1 2 …

Anuglar中正確導入RxJS庫

Anuglar中正確導入RxJS庫 目前Angular2中的已經內建支持RxJS,所以我們在使用的時候可以直接導入使用了。 理解操作符導? 在使用創建依賴于 RxJS 組件,服務,指令等等時, 你可能遇到處理運算符導?的問 題。 在項?中引?操作符最主要的?式像下?這樣導?: import rxj…

1495: 蛇行矩陣

1495: 蛇行矩陣 Description 蛇形矩陣是由1開始的自然數依次排列成的一個矩陣上三角形。 Input 本題有多組數據&#xff0c;每組數據由一個正整數N組成。&#xff08;N不大于100&#xff09; Output 對于每一組數據&#xff0c;輸出一個N行的蛇形矩陣。兩組輸出之間不要額…

遞歸基礎之N皇后問題

遞歸基礎之N皇后問題 Description 在nn 格的棋盤上放置彼此不受攻擊的n 個皇后。按照國際象棋的規則&#xff0c;皇后可以攻擊與之 處在同一行或同一列或同一斜線上的棋子。n后問題等價于在nn格的棋盤上放置n個皇后&#xff0c; 任何2 個皇后不放在同一行或同一列或同一斜線上…

X86和X86_64和AMD64的由來

為什么叫X86和X86_64和AMD64 為什么大家叫x86為32位系統呢 相信大家在大學里面有很多人都玩過8086&#xff08;微處理器&#xff09;&#xff0c;這是一個可編程的系統&#xff0c;他是由intel開發的&#xff0c;英特爾出了劃時代的8086之后&#xff0c;后來使用該架構出了80…

回爐-熄燈問題

進來突然意識到算法的重要性&#xff0c;可惜已經沒有充足的時間去進行專業的訓練了&#xff0c;只能慢慢擠時間做幾個題練習一下聊以安慰&#xff0c;希望能多堅持幾天吧&#xff0c;奉勸各位想學算法的同學一定要趁早啊。 poj1222 解析見郭煒老師的程序設計與算法&#xff…

ngrx初識

ngrx初識 在使用之前需要安裝ngrx npm install @ngrx/store --save 或者 yarn add @ngrx/store ngrx/store:保存了ReduxAPI的核心概念,使用RxJS擴展的Redux實現。使用可觀察對象來簡化了監聽事件的訂閱等操作。 dispatch&reducer&state dispatcher,reducer,state…

回爐-特殊密碼鎖

題目&#xff1a;特殊密碼鎖 001:特殊密碼鎖 描述 有一種特殊的二進制密碼鎖&#xff0c;由n個相連的按鈕組成&#xff08;n<30&#xff09;&#xff0c;按鈕有凹/凸兩種狀態&#xff0c;用手按按鈕會改變其狀態。 然而讓人頭疼的是&#xff0c;當你按一個按鈕時&#x…

Angular的NgModule

Angular的NgModule NgModule作為Angular模塊的核心,也是組織者,官方有很長的文檔來介紹他,包括每一個API。 @NgModule文件的定義方式 import { BrowserModule } from @angular/platform-browser; import { NgModule } from @angular/core;import { AppComponent } from ./ap…

回爐-撥鐘問題

題目&#xff1a;撥鐘問題 1166:撥鐘問題 描述 有9個時鐘&#xff0c;排成一個3*3的矩陣。 |-------| |-------| |-------| | | | | | | | |---O | |---O | | O | | | | | | | |-------| |-------| …