JavaScript中的Promise小結

_shine發表於2018-01-22

1、 什麼是Promise

   Promise是抽象非同步處理物件以及對其進行各種操作的元件。Promise並不是從JavaScript中發祥的概念。Promise最初被提出是在 E語言中, 它是基於並列/並行處理設計的一種程式語言。現在JavaScript也擁有了這種特性,這就是本文所介紹的JavaScript Promise。另外,如果說到基於JavaScript的非同步處理,我想大多數都會想到利用回撥函式。 Promise是一個類,可以建立例項代表承諾,而什麼時候會用到承諾 ,一般是非同步任務,就是需要很長時間執行的時間

Promise的狀態

用new Promise 例項化的promise物件有以下三個狀態。

  • Fulfilled resolve(成功)時。此時會呼叫 onFulfilled
  • Rejected reject(失敗)時。此時會呼叫 onRejected
  • Pending 既不是resolve也不是reject的狀態。也就是promise物件剛被建立後的初始化狀態等

promise物件的狀態,從Pending轉換為Fulfilled或Rejected之後, 這個promise物件的狀態就不會再發生任何變化。也就是說,Promise與Event等不同,在.then 後執行的函式可以肯定地說只會被呼叫一次。另外,Fulfilled和Rejected這兩個中的任一狀態都可以表示為Settled(不變的)。

Promise的建立

一般情況下我們都會使用 new Promise() 來建立promise物件,但是除此之外我們也可以使用其他方法。 在這裡,我們將會學習如何使用 Promise.resolve 和 Promise.reject這兩個方法。

let Promise = require('./Promise');
let p1 = new Promise(function(resolve,reject){
    setTimeout(function(){
     let num = Math.random();//生成一個隨機數
      console.log(num);
      if(num>.5){
       resolve('大成功');
     }else{
       reject('小失敗');
     }
    },2000);
});
p1.then(function(value){
    console.log('成功1=',value);
},function(reason){
    console.log('失敗1=',reason);
});
p1.then(function(value){
    console.log('成功2=',value);
},function(reason){
    console.log('失敗2=',reason);
});
複製程式碼

Promimst 函式

  • Promise.all Promise.all 接收一個 promise物件的陣列作為引數,當這個陣列裡的所有promise物件全部變為resolve或reject狀態的時候,它才會去呼叫 .then 方法。
function getURL(URL) {
    return new Promise(function (resolve, reject) {
        var req = new XMLHttpRequest();
        req.open('GET', URL, true);
        req.onload = function () {
            if (req.status === 200) {
                resolve(req.responseText);
            } else {
                reject(new Error(req.statusText));
            }
        };
        req.onerror = function () {
            reject(new Error(req.statusText));
        };
        req.send();
    });
}
var request = {
        comment: function getComment() {
            return getURL('http://azu.github.io/promises-book/json/comment.json').then(JSON.parse);
        },
        people: function getPeople() {
            return getURL('http://azu.github.io/promises-book/json/people.json').then(JSON.parse);
        }
    };
function main() {
    return Promise.all([request.comment(), request.people()]);
}
// 執行示例
main().then(function (value) {
    console.log(value);
}).catch(function(error){
    console.log(error);
});
複製程式碼
  • Promise.race 它的使用方法和Promise.all一樣,接收一個promise物件陣列為引數。 Promise.all 在接收到的所有的物件promise都變為 FulFilled 或者 Rejected 狀態之後才會繼續進行後面的處理, 與之相對的是 Promise.race 只要有一個promise物件進入 FulFilled 或者 Rejected 狀態的話,就會繼續進行後面的處理。
// `delay`毫秒後執行resolve
function timerPromisefy(delay) {
    return new Promise(function (resolve) {
        setTimeout(function () {
            resolve(delay);
        }, delay);
    });
}
// 任何一個promise變為resolve或reject 的話程式就停止執行
Promise.race([
    timerPromisefy(1),
    timerPromisefy(32),
    timerPromisefy(64),
    timerPromisefy(128)
]).then(function (value) {
    console.log(value);    // => 1
});
複製程式碼

Promise常見庫

介紹一些第三方實現的和Promise相容的類庫

  • 類庫 Q 實現了 Promises 和 Deferreds 等規範。 它自2009年開始開發,還提供了面向Node.js的檔案IO API Q-IO 等, 是一個在很多場景下都能用得到的類庫,在angular.js裡的promise就是用的q。
//let Q = require('q');
let Q = {
  defer(){
    let success,error;
    return {
      resolve(data){
        success(data);
      },
      reject(err){
        error(err);
      },
      promise:{
        then(onFulfilled,onRejected){
          success = onFulfilled;
          error = onRejected;
        }
      }
    }
  }
}
let fs = require('fs');
function readFile(filename){
   let defer = Q.defer();
   fs.readFile(filename,'utf8',function(err,data){
      if(err)
        defer.reject(err);
      else{
        defer.resolve(data);
      }
   });
   return defer.promise;
}
readFile('1.txt').then(function(data){
  console.log(data);
});
複製程式碼
  • petkaantonov/bluebird 這個類庫除了相容 Promise 規範之外,還擴充套件了取消promise物件的執行,取得promise的執行進度,以及錯誤處理的擴充套件檢測等非常豐富的功能,此外它在實現上還在效能問題下了很大的功夫。
/**
 * bluebird是世界最快的promise庫
 * //它能把任意的通過回撥函式實現的非同步API換成promiseapi
 */
let Promise = require('bluebird');
let fs = require('fs');
function promisifyAll(obj) {
  for (let key in obj) {
    if (obj.hasOwnProperty(key) && typeof obj[key] == 'function') {
      obj[key+'Async'] = Promise.promisify(obj[key]);
    }
  }
}
//它會遍歷物件上面的所有方法,然後對每個方法新增一個新的方法 Async
promisifyAll(fs);
fs.readFileAsync('./1.txt', 'utf8').then(data => console.log(data));
複製程式碼

Q 和 Bluebird 這兩個類庫除了都能在瀏覽器裡執行之外,充實的API reference也是其特徵。

相關文章