2016-04-10 117 views
3

我期望以下代碼段的輸出爲1, 2, 3, 4。但是,實際的輸出訂單是1, 4, 3, 2ES6承諾執行訂單

self.promiseChain = new Promise(function (resolve, reject) { 
    setTimeout(resolve, 4000); 
}).then(function() { 
    console.log(1); 
}); 

self.promiseChain.then(function() { 
    return new Promise(function (resolve, reject) { 
    setTimeout(resolve, 3000); 
    }).then(function() { 
    console.log(2); 
    }); 
}); 

self.promiseChain.then(function() { 
    return new Promise(function (resolve, reject) { 
    setTimeout(resolve, 2000); 
    }).then(function() { 
    console.log(3); 
    }); 
}); 
self.promiseChain.then(function() { 
    return new Promise(function (resolve, reject) { 
    setTimeout(resolve, 200); 
    }).then(function() { 
    console.log(4); 
    }); 
}); 

http://www.es6fiddle.net/imu5bhoj/

一切我讀過有關承諾,表明它應該可以得到這樣的「平」鏈中所需的順序。顯然我錯過了一些細節?有人能幫助我指出正確的方向嗎?

這是一個小提琴(http://www.es6fiddle.net/imu6vh1o/)如何以非平坦的方式做到這一點,但很難推理,並使順序鏈接尷尬。

我已經在堆棧溢出上搜索了類似的問題,但他們都沒有回答這個問題,一般使用一個簡單的例子(我可以找到)。

+1

您的意思是'self.promiseChain = self.promiseChain.then ...'? – elclanrs

+0

Yup @elclanrs,看起來像是我的問題! –

回答

8

您剛剛附加了三個.then()處理程序到完全相同的self.promiseChain承諾。這是分支,而不是鏈接。承諾,這些是非常不同的行爲。這些是三個處理程序,當self.promiseChain已解決時,所有這些處理程序都會立即被調用(無需等待結果)。所以,最終的三個異步操作將並行運行,並在每次完成時結束,從而得到您看到的結果。

如果你想要對這四個操作進行排序,那麼你必須將它們鏈接到另一個,而不是所有鏈接在同一個承諾上。記住.then()返回一個新的承諾,這是你想要鏈接以便對事物進行排序的返回承諾。

你這樣做:

var p = somePromise(); 

p.then(fn1); 
p.then(fn2); 
p.then(fn3); 

這將觸發fn1fn2fn3在基本相同的時間和fn2不會等待fn1承諾來解決。

如果要排序的操作,那麼您希望這種類型的邏輯:

var p = somePromise(); 

p.then(fn1).then(fn2).then(fn3); 

直到fn1承諾做這將不執行fn2和直到fn2承諾進行,將不執行fn3 - 從而對異步操作進行排序。

下面是如果它們是一個接一個地被測序的情況。實際上,你可以運行這段代碼(但要有耐心,因爲它需要10秒的運行):

var self = {}; 
 

 
self.promiseChain = new Promise(function (resolve, reject) { 
 
    setTimeout(resolve, 4000); 
 
}).then(function() { 
 
    log(1); 
 
}); 
 

 
var p = self.promiseChain.then(function() { 
 
    return new Promise(function (resolve, reject) { 
 
    setTimeout(resolve, 3000); 
 
    }).then(function() { 
 
    log(2); 
 
    }); 
 
}); 
 

 
p = p.then(function() { 
 
    return new Promise(function (resolve, reject) { 
 
    setTimeout(resolve, 2000); 
 
    }).then(function() { 
 
    log(3); 
 
    }); 
 
}); 
 
p = p.then(function() { 
 
    return new Promise(function (resolve, reject) { 
 
    setTimeout(resolve, 200); 
 
    }).then(function() { 
 
    log(4); 
 
    }); 
 
}); 
 

 
p.then(function() { 
 
    // last promise is done now 
 
    log("all done"); 
 
}); 
 

 
function log(x) { 
 
    var div = document.createElement("div"); 
 
    div.innerHTML = x; 
 
    document.body.appendChild(div); 
 
}

見其它類似的答案:

Execute native js promise in series

Understanding javascript promises; stacks and chaining

Is there a difference between promise.then.then vs promise.then; promise.then

+0

謝謝@ jfriend00!我想我可以理解downvotes。猜猜我應該刷新我的stackoverflow搜索技能。無論如何,我的誤解現在已經很清楚,我終於可以從鍵盤上擡起我的頭了! –