Promise快餐

Promise 是異步編程的一種解決方案,其餘的異步編程解決方案還有——回調函數事件監聽發佈訂閱,以及ES6新增的Generatorjavascript

http://www.ruanyifeng.com/blo...
http://es6.ruanyifeng.com/#do...html

Promise的狀態

  1. Pending(進行中)java

  2. Resolved (已完成)node

  3. Rejected (已失敗)es6

Promise的特色

  1. 對象的狀態不受外界影響。數據庫

  2. 一旦狀態改變,就不會再變,任什麼時候候均可以獲得這個結果。編程


Promise的用法

var promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 異步操做成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

注意:json

resovle和reject函數都是由js引擎提供的函數不用本身定義。數組

其中 resovle函數的做用是將Promise對象從進行中狀態轉換爲已完成reject函數將Promise對象從進行中狀態轉換爲已失敗狀態。promise


Promise.prototype.then()

Promise 實例具備then方法,then方法是定義在原型對象Promise.prototype上的,它的做用是爲 Promise 實例添加狀態改變時的回調函數。

延續上面的代碼:

promise.then(function(res) {
    console.log(res)
}, function(err) {
    console.log(err)
})

then對象接收兩個回調函數做爲參數,第一個回調函數是resovle的回調,第二個回調函數是reject的回調。即,一個用於處理狀態爲已完成的邏輯,另外一個用於處理已失敗的邏輯。

一個Ajax請求的例子:

var getJSON = function(url) {
  var promise = new Promise(function(resolve, reject){
    var client = new XMLHttpRequest();
    client.open("GET", url);
    client.onreadystatechange = handler;
    client.responseType = "json";
    client.setRequestHeader("Accept", "application/json");
    client.send();

    function handler() {
      if (this.readyState !== 4) {
        return;
      }
      if (this.status === 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    };
  });

  return promise;
};

getJSON("/posts.json").then(function(json) {
  console.log('Contents: ' + json);
}, function(error) {
  console.error('出錯了', error);
});

Promise.prototype.catch()

Promise.prototype.catch方法是.then(null, rejection)的別名,用於指定發生錯誤時的回調函數。不是指then方法的別名而是指resovle的回調函數爲null的then方法的別名。

一般推薦使用catch方法來捕獲異常,而不是使用reject的回調函數。

// 不推薦的寫法
promise
  .then(function(data) {
    // success
  }, function(err) {
    // error
  });

// 推薦的寫法
promise
  .then(function(data) {
    // success
  })
  .catch(function(err) {
    // error
  });

使用catch方法來接收錯誤信息的好處是,Promise 對象的錯誤具備「冒泡」性質,會一直向後傳遞,直到被捕獲爲止。因此一個catch能夠捕獲鏈式調用中多個Promise對象拋出的異常。

鏈式調用

當有幾個異步操做須要鏈式調用時,promise是支持的。

一個簡單的鏈式調用的例子:

getJSON("/post/1.json").then(function(post) {
  return getJSON(post.commentURL);
}).then(function funcA(comments) {
  console.log("Resolved: ", comments);
}, function funcB(err){
  console.log("Rejected: ", err);
});

Promise的then函數,返回的是一個新的Promise對象。若是返回的對象不是Promise對象會是什麼效果呢?
如下是一些測驗代碼:

var promise = new Promise(function(resolve, reject) {
  let a = '111';
    resolve(a);
});

promise.then(function(res) {
    return null;
}).then(function(res){
    console.log(res);
}).catch(function(err) {
    console.log(err);
})
// null
var b = function() {
    console.log('bb');
}

var promise = new Promise(function(resolve, reject) {
  let a = '111';
    resolve(a);
});

promise.then(function(res) {
    return b();
}).then(function(res){
    console.log(res);
})
// bb
// undefined

能夠看出,若是then retrun的不是一個Promise函數時,並不會報錯,也沒有拋出異常,至關於一個沒有執行reject和resovle的Promise對象(我的理解,有失偏頗。望自慎重,擇善從之。)。

Promise.all()

在某些時候,咱們須要執行多個異步操做。這些異步操做可能有如下幾種關係:

  1. 互不關聯

  2. 逐個依賴

  3. 部分依賴

  4. 結果依賴(指須要得到因此返回的結果進行下一步的操做)

Promise.all方法用於將多個 Promise 實例,包裝成一個新的 Promise 實例。能夠用來解決上面的4關係。
互不關聯最好分開調用,部分依賴、逐個依賴用鏈式調用。

Promise.all接收一個Promise數組做爲參數,即數組中的值都是Promise對象,若是不是就會先調用Promise.resovle方法,將參數轉爲Promise實例。

// 生成一個Promise對象的數組
var promises = [2, 3, 5, 7, 11, 13].map(function (id) {
  return getJSON('/post/' + id + ".json");
});

Promise.all(promises).then(function (posts) {
  // ...
}).catch(function(reason){
  // ...
});

只有當全部的Promise對象都返回resovle時纔會執行then方法,只要有一個Pormise對象返回的是reject,就執行catch。

ps: 還有Promise.race()方法,此方法和Promise.all()不一樣之處時,只要傳入的Promise數組中有一個實例率先改變狀態,p的狀態就跟着改變。那個率先改變的 Promise 實例的返回值,就傳遞給p的回調函數。可用於限制請求的最大反應時間。

const p = Promise.race([
  fetch('/resource-that-may-take-a-while'),
  new Promise(function (resolve, reject) {
    setTimeout(() => reject(new Error('request timeout')), 5000)
  })
]);
p.then(response => console.log(response));
p.catch(error => console.log(error));
// 若是超過5秒就返回請求超時

Promise.resolve()和Promise.reject()

這兩個方法返回一個新的Promise實例,resovle方法返回的實例狀態爲resolve,同理reject方法返回reject。
都接收一個參數做爲現有的對象,此參數能夠爲任何值包括null,undefined。
根據接收的參數,兩種方法都會作出不一樣的處理。在此不作詳細的介紹了,有興趣的能夠去看看

http://es6.ruanyifeng.com/#do...

Promise.resolve('foo')
// 等價於
new Promise(resolve => resolve('foo'))

finally()

此方法用於最後執行,不Promise的狀態如何,都會執行的操做(還有這種操做?)。在node中可用於關閉服務器或者數據庫鏈接。在瀏覽器中可用於須要在異步函數返回以後執行的操做。

var p = new Promise(function(resovle.reject){
    resovle('is resovle');
});

p.then(function(res) {
    console.log(res) 
}).finally(function() {
    console.log('is finally');
})
相關文章
相關標籤/搜索