關於Promise:你可能不知道的6件事

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 會認爲已經修復了錯誤,並準備進入下一個皮層。

五、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 纔會顯示。若是要在已經存在的異步代碼中引入更多的依賴,這是一個很便利的方式。例如,你發現用戶會話已經超時了,所以,你可能想要在繼續執行後面的代碼以前發起第二次登陸。

六、resolved 狀態的 Promise 不會當即執行

運行下面的代碼會彈出什麼呢?

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

相關文章
相關標籤/搜索