深入理解JS異步編程三(promise)

jQuery

原本寫一個小動畫我們可能是這樣的

$('.animateEle').animate({
  opacity:'.5'
}, 4000,function(){
  $('.animateEle2').animate({
    width:'100px'
  },2000,function(){
    $('.animateEle3').animate({
      height:'0'
    },2000);
  });
});

但是如果我們使用promis對象的話,就可以使得代碼更加簡單易懂

var animate1 = function() {
  return $('.animateEle1').animate({opacity:'.5'},4000).promise();
};
var animate2 = function() {
  return $('.animateEle2').animate({width:'100px'},2000).promise();
};
var animate3 = function(){
  return $('.animateEle3').animate({height:'0'},2000).promise();
};
$.when(animate1()).then(animate2).then(animate3);

對比上面兩段代碼,回調的形式相比promise,後期較難維護,層層嵌套,出錯不好定位,反直覺。

Promise對象方法

對於DOM,動畫,ajax相關方法,都可以使用 promise 方法。調用 promise 方法,返回的是 promise 對象。可以鏈式調用 promise 方法。

比如jquery中的ajax的 $.post $.get $.ajax 等方法,實際上都是默認調用了promise方法,然後返回了一個promise對象

promise對象常見的方法有三個 : done , fail , then 。

$.get('/',{}).done(function(data){
    console.log('success');
}).fail(function(){
    console.log('fail');
});

query 這裏的接口方法太多了,就跟早期的事件方法綁定一樣, live , delegate , bind ,最終還是歸爲 on。

deferred對象方法

var  promisepbj = new $.Deferred();

promisepbj.done(function() {
console.log('haha,done');
}).fail(function() {
console.log('失敗了');
}).always(function(res) {
console.log('我總是被執行啦');
});

//使用resolve或者reject就可以調用defferred對象了
promisepobj.resolve();
//promisepobj.reject();

resolve 方法會觸發 done 的回調執行, reject 會觸發 fail 的回調,對於 always 方法,deferred 對象,無論是 resolve 還是 reject ,都會觸發該方法的回調。

ES6 Promise

前面講了很多jquery的promise實現,$.Deferred 和 ES2015 的 Promise 是不同的東西,因爲前者不符合 Promises/A+ 規範。 Promise 對象在 EMCAScript 2015 當中已經成爲標準。現在要來談談馬上要成爲主流趨勢的es6原生promise對象,首先貼一個很詳細的es6 promise的小書,基本你知道的不知道都在裏面 http://liubin.org/promises-book/#introduction

阮一峯大神的關於ES6的promise解釋 http://es6.ruanyifeng.com/#docs/promise

定義

所謂Promise,簡單說就是一個容器,裏面保存着某個未來纔會結束的事件(通常是一個異步操作)的結果。
特點:

  • 有三種狀態:Pending(進行中)、Resolved(已完成,又稱Fulfilled)和Rejected(已失敗)。
  • 一旦狀態改變,就不會再變,任何時候都可以得到這個結果。Promise對象的狀態改變,只有兩種可能:從Pending變爲Resolved和從Pending變爲Rejected。只要這兩種情況發生,狀態就凝固了,會一直保持這個結果。就算改變已經發生了,你再對Promise對象添加回調函數,也會立即得到這個結果。這與事件(Event)完全不同,事件的特點是,如果你錯過了它,再去監聽,是得不到結果的。
var promise = new Promise(function(resolve, reject) {
  // ... some code

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

then方法

then方法可以接受兩個回調函數作爲參數。第一個回調函數是Promise對象的狀態變爲Resolved時調用,第二個回調函數是Promise對象的狀態變爲Reject時調用。其中,第二個函數是可選的,不一定要提供。這兩個函數都接受Promise對象傳出的值作爲參數。

function timeout(ms) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, ms, 'done');
  });
}

timeout(100).then((value) => {
  console.log(value);
});

異常處理

  異常處理一直是回調的難題,而promise提供了非常方便的catch方法:在一次promise調用中,任何的環節發生reject,都可以在最終的catch中捕獲到:

Promise.resolve().then(function(){
    return loadImage(img1);
}).then(function(){
    return loadImage(img2);
}).then(function(){
    return loadImage(img3);
}).catch(function(err){
    //錯誤處理
})

基本的 api

  • Promise.resolve()
  • Promise.reject()
  • Promise.prototype.then()
  • Promise.prototype.catch()
  • Promise.all()

- Promise.race()

具體的很多的用法可以參考阮一峯的 http://es6.ruanyifeng.com/#docs/promise 入門教程

發佈了48 篇原創文章 · 獲贊 29 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章