深刻學習Promise調用鏈

前言

使用Promise中,鏈式的調用對於控制異步執行很重要。css

鏈式調用

在jQuery的使用中,咱們經常使用下面的代碼node

$('#app').show().css("color","red");

這是由於jQuery的對象在調用上述方法的時候,會return此對象自己, 以方便後面能夠繼續調用此對象的方法。segmentfault

jQuery.fn.css = function(prop, value) {
    ......
    return this;
}

jQuery.fn.show = function() {
    ......
    return this;
}

Promise的鏈式調用

Promise是支持鏈式調用的,可是它是不一樣於上面jQuery的鏈式。jQeury是調用方法返回自身,可是Promise是調用方法後返回一個新的Promise。promise

const promise = new Promise((resolve, reject) => {
    resolve('ok');
})

const promise$1 = promise.then(() => {console.log()});

promise$1 === promise // false

能夠看到上面的promise$1是不等於promise的,若是能夠在node.js 或者在瀏覽器中進行斷點調試的話,還能看到promise$1的初始化狀態是pending的。
clipboard.png瀏覽器

當Promise的實例使用then, catch, finally添加完回調方法之後,會返回一個初始化狀態爲pending的Promise的實例對象。此對象的狀態咱們在外部的程序是沒法進行改變的,它的狀態取決於前面所註冊的回調方法的執行狀況。 當回調方法運行正常,沒有產生錯誤或者異常,返回的值除Promise實例與自己(返回自己將會報錯),返回的Promise的實例對象狀態會變成resolved, 若是有錯誤或者異常,則會把狀態變爲rejected。固然了返回值是Promise的實例對象,那麼次Promise實例對象的狀態取決於返回的Promise實例對象的狀態。 app

下圖以then爲例展現promise鏈式調用運行的流程異步

clipboard.png

示例分析

1. 調用鏈then的執行順序
const promise$0 = Promise.resolve('resolve_0');
const promise$1 = new Promise((resolve, reject) => {resolve('resolve_1')})
promise$0.then((val) => { console.log(val) }).then(() => { console.log('continue') });
promise$1.then((val) => { console.log(val) });       
       
//輸出結果: resolve_0  resolve_1  continue

promise$0與promise$1在使用then添加回掉函數以前,狀態已經從pending變爲resolved,它們添加的回掉函數會被當即添加到Promise的運行隊列,promise$0.then((val) => { console.log(val) })返回的Promise實例須要等待所註冊的回調函數成功執行完畢之後,此Promise的狀態才從pending變爲resolved。 Promise的運行機制請參考: Promise的運行機制函數

2. 值穿透
const promise = Promise.resolve('ok');

promise.then().then((val) => {console.log(val)});

// ok

因爲promise經過then沒有成功添加回調函數,發生了值穿透。this

3. 狀態傳遞
const promise = Promise.resolve('complete');

promise.then((val) => { 
    return new Promise ((resolve) => { 
             resolve(val)
            console.log(val, 1); 
        })
    })
    .then((val) => {console.log(val, 2)})
// complete 1 complete 2

咱們把Promise暫命名(Pa), 經過promise.then返回的Promise(暫命名Pb), Pb狀態須要根據Pathen所註冊回調方法的運行,其回調方法返回一個新的Promise(暫命名Pc),因爲返回的是Promise。Pb的狀態變成取決於Pc的狀態, 當Pc的狀態變化爲resolved之後,Pb的狀態也變化爲resolved。spa

4. 巧妙的異常處理
var promise = Promise.resolve('ok');

promise.then(() => {
    throw new Error('error');
}).then(() => {
    console.log('continue');
}).then(() => {
    console.log('again');
}).catch(() => {

}).then(() => {
  console.log('completed')
})
// completed

在then所註冊的回調方法,發生異常之後,後續的Promise調用鏈的狀態都是rejected,致使後續的then(resolve)不會被推入Promise的運行隊列,也就不會被運行,直到這個錯誤被then(,reject) 或者catch捕獲。 而使用(then(,reject)) 或者catch註冊回調方法又會返回一個新的Promise,此Promise的狀態又只與它們所註冊的回調方法的執行相關。不會受到前面的影響。

相關文章
相關標籤/搜索