FROM ME :javascript
文章介紹了6個Promise的知識點:java
一、then() 返回一個 forked Promise(分叉的 Promise):返回的有兩種狀況;
二、回調函數應該傳遞結果:在 promise 的上下文中,回調函數像普通的回調函數同樣傳遞結果,返回的結果傳給下一個回調函數;
三、只能捕獲來自上一級的異常
四、錯誤能被恢復:在一個錯誤回調中,若是沒有從新拋出錯誤,promise 會認爲你已經恢復了該錯誤,promise 的狀態會轉變爲 resolved。
五、Promise 能被暫停:爲了暫停當前的 promise,或者要它等待另外一個 promise 完成,只須要簡單地在 then()
函數中返回另外一個 promise。
六、resolved 狀態的 Promise 不會當即執行git
原文:Six Things You Might Not Know About Promisesgithub
譯文:關於Promise:你可能不知道的6件事web
Promise 是一個很是簡單的概念,即便你沒有機會使用 Promise,你也可能閱讀過一些關於 Promise 的文章。
Promise 的價值在於使得異步代碼以一個更可讀的風格結構化,而不是因異步函數嵌套顯得混亂不堪。這篇文章會接觸到 6 個你可能不知道的關於 Promise 的事。數組
開始列舉以前,先看看怎麼建立 Promise:promise
var p = new Promise(function(resolve, reject) { resolve("hello world"); }); p.then(function(str) { alert(str); });
then()
返回一個 forked Promise(分叉的 Promise)下面兩段代碼有什麼不一樣?異步
// Exhibit A var p = new Promise(/*...*/); p.then(func1); p.then(func2); // Exhibit B var p = new Promise(/*...*/); p.then(func1) .then(func2);
若是你認爲兩段代碼等價,那麼你可能認爲 promise 僅僅就是一維回調函數的數組。然而,這兩段代碼並不等價。p
每次調用 then()
都會返回一個 forked promise。所以,在A中,若是 func1
拋出一個異常,func2
依然能執行,而在B中,func2
不會被執行,由於第一次調用返回了一個新的 promise,因爲func1
中拋出異常,這個 promise 被 rejected了,結果 func2
被跳過不執行了。函數
下面的代碼會 alert 什麼?spa
var p = new Promise(function(resolve, reject) { resolve("hello world"); }); p.then(function(str) {}) .then(function(str) { alert(str); });
第二個 then()
中的alert不是顯示任何東西,由於在 promise 的上下文中,回調函數像普通的回調函數同樣傳遞結果。promise 指望你的回調函數或者返回同一個結果,或者返回其它結果,返回的結果會被傳給下一個回調。
這和適配器傳遞結果的思想同樣,看下面的示例:
var feetToMetres = function(ft) { return ft*12*0.0254 }; var p = new Promise(/*...*/); p.then(feetToMetres) .then(function(metres) { alert(metres); });
下面的兩段代碼有什麼不一樣:
// Exhibit A new Promise(function(resolve, reject) { resolve("hello world"); }) .then( function(str) { throw new Error("uh oh"); }, undefined ) .then( undefined, function(error) { alert(error); } );
// Exhibit B new Promise(function(resolve, reject) { resolve("hello world"); }) .then( function(str) { throw new Error("uh oh"); }, function(error) { alert(error); } );
在A中,當第一個 then
拋出異常時,第二個 then
能捕獲到該異常,並會彈出 'uh oh'。這符合只捕獲來自上一級異常的規則。
在B中,正確的回調函數和錯誤的回調函數在同一級,也就是說,儘管在回調中拋出了異常,可是這個異常不會被捕獲。事實上,B中的錯誤回調只有在 promise 被 rejected 或者 promise 自身拋出一個異常時纔會被執行。
在一個錯誤回調中,若是沒有從新拋出錯誤,promise 會認爲你已經恢復了該錯誤,promise 的狀態會轉變爲 resolved。在下面的例子中,會彈出’I am saved’ 是由於第一個 then()
中的錯誤回調函數並無從新拋出異常。
var p = new Promise(function(resolve,reject){ reject(new Error('pebkac')); }); p.then( undefined, function(error){ } ) .then( function(str){ alert('I am saved!'); }, function(error){ alert('Bad computer!'); } );
Promise 可被視爲洋蔥的皮層,每一次調用 then
都會被添加一層皮層,每個皮層表示一個能被處理的狀態,在皮層被處理以後,promise 會認爲已經修復了錯誤,並準備進入下一個皮層。
僅僅由於你已經在一個 then()
函數中執行過代碼,並不意味着你不可以暫停 promise 去作其餘事情。爲了暫停當前的 promise,或者要它等待另外一個 promise 完成,只須要簡單地在 then()
函數中返回另外一個 promise。
var = new Promise(/*...*/); p.then(function(str){ if(!loggedIn){ return new Promise(/*...*/); } }) .then(function(str){ alert("Done!"); });
在上面的代碼中,直到新的 promise 的狀態是 resolved解析後,alert 纔會顯示。若是要在已經存在的異步代碼中引入更多的依賴,這是一個很便利的方式。例如,你發現用戶會話已經超時了,所以,你可能想要在繼續執行後面的代碼以前發起第二次登陸。
運行下面的代碼會彈出什麼呢?
function runme() { var i = 0; new Promise(function(resolve) { resolve(); }) .then(function() { i += 2; }); alert(i); }
你可能會認爲彈出2,由於 promise 已是 resolved ,then()
會當即執行(同步)。然而,promise 規範要求全部回調都是異步的,所以,alert 執行時 i
的值尚未被修改。
Promise 的正確打開方式
Promise/A+
Promise 教程
JavaScript Promises 102 - The 4 Promise Methods