JavaScript Promise查缺補(bǔ)漏

image

原文鏈接

Promise簡(jiǎn)介

ECMAscript6原生提供了Promise對(duì)象,由瀏覽器直接支持,目前大多數(shù)瀏覽器都已經(jīng)實(shí)現(xiàn)了,低版本瀏覽器可以使用es6-promise庫(kù)來(lái)填平兼容性問(wèn)題。Promise最大的好處是把執(zhí)行代碼和處理代碼分離開(kāi),使異步操作邏輯更加清晰。

Promise特點(diǎn)

1、對(duì)象的狀態(tài)不受外界影響
Promise對(duì)象代表一個(gè)異步操作,有三種狀態(tài):

  • pending - 初始狀態(tài)。
  • fulfilled - 操作成功完成。
  • rejected - 操作失敗。

只有異步操作的結(jié)果可以決定當(dāng)前是哪一種狀態(tài),其他操作都不會(huì)影響狀態(tài)改變,這也是Promise最本質(zhì)的特性,對(duì)于調(diào)用者的一種承諾

2、一旦狀態(tài)改變,就不會(huì)再變
Promise對(duì)象的狀態(tài)改變,只有兩種情況:從Pending變?yōu)镽esolved和從Pending變?yōu)镽ejected。只要這兩種情況發(fā)生,狀態(tài)就會(huì)固定,不會(huì)再變了,會(huì)一直保持這個(gè)結(jié)果,與事件不同的是,就算改變已經(jīng)發(fā)生了,再對(duì)Promise對(duì)象添加回調(diào)函數(shù),也會(huì)立即得到這個(gè)結(jié)果,而事件一旦錯(cuò)過(guò)再去監(jiān)聽(tīng),就不會(huì)得到結(jié)果。

Promise優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

  • 有了Promise對(duì)象,就可以將異步操作以同步操作的流程表達(dá)出來(lái),避免了層層嵌套的回調(diào)函數(shù)Promise
  • 對(duì)象提供統(tǒng)一的接口,使得控制異步操作更加容易

缺點(diǎn):

  • 無(wú)法取消 Promise,一旦新建它就會(huì)立即執(zhí)行,無(wú)法中途取消
  • 如果不設(shè)置回調(diào)函數(shù),Promise內(nèi)部拋出的錯(cuò)誤,不會(huì)反應(yīng)到外部
  • 當(dāng)處于Pending狀態(tài)時(shí),無(wú)法得知目前進(jìn)展到哪一個(gè)階段(剛剛開(kāi)始或者即將完成)

Promise.prototype.then

Promise.prototype.then方法返回的是一個(gè)新的Promise對(duì)象,因此可以采用鏈?zhǔn)綄?xiě)法

ajax("http://www.bestvist.com").then((json) => {
    return json.post;
}).then((post) => {
    // post處理
});

代碼中使用then方法,指定了兩個(gè)回調(diào)函數(shù)。第一個(gè)回調(diào)函數(shù)完成后,會(huì)將返回結(jié)果作為參數(shù),傳入第二個(gè)then中的回調(diào)函數(shù)執(zhí)行。

ajax("http://www.bestvist.com").then((jsonURL) => {
        return ajax(jsonURL);
}).then((post) => {
        // post處理
});

如果第一個(gè)回調(diào)函數(shù)返回的是Promise對(duì)象,后一個(gè)回調(diào)函數(shù)會(huì)等待該P(yáng)romise對(duì)象的運(yùn)行結(jié)果,等Promise運(yùn)行結(jié)果返回,再進(jìn)一步調(diào)用。
這種設(shè)計(jì)使得嵌套的異步操作,可以被很容易得改寫(xiě),把回調(diào)函數(shù)的"橫向發(fā)展"改為了"向下發(fā)展"。

Promise.prototype.catch

Promise.prototype.catch錯(cuò)誤捕捉方法是Promise.prototype.then(null, rejection)的別名,用來(lái)指定發(fā)生錯(cuò)誤時(shí)的處理函數(shù)。

ajax("http://www.bestvist.com").then((post) => {
    throw Error();
}).catch((error) => {
    // 捕捉回調(diào)函數(shù)運(yùn)行時(shí)發(fā)生的錯(cuò)誤進(jìn)行處理
    console.log('error:' + error);
});

Promise對(duì)象的錯(cuò)誤具有"冒泡"性質(zhì),會(huì)一直向后傳遞,直到被捕獲為止。

ajax("http://www.bestvist.com").then((jsonURL) => {
    return ajax(jsonURL);
}).then((comments) => {
    throw Error();
}).catch((error) => {
    // 處理前兩個(gè)回調(diào)函數(shù)的錯(cuò)誤
        console.log('error:' + error);
});

Promise.resolve

Promise.resolve方法可以將現(xiàn)有對(duì)象轉(zhuǎn)為Promise對(duì)象。如果Promise.resolve方法的參數(shù),不是thenable 對(duì)象(具有then方法的對(duì)象 ),則返回一個(gè)新的Promise對(duì)象,且它的狀態(tài)為fulfilled。

const resolve = Promise.resolve('promise resolve');
resolve.then((s)=>{
  console.log(s)
});

輸出結(jié)果:
promise resolve

如果Promise對(duì)象的實(shí)例狀態(tài)為fulfilled,回調(diào)函數(shù)會(huì)立即執(zhí)行,Promise.resolve方法的參數(shù)就是回調(diào)函數(shù)的參數(shù)。
如果Promise.resolve方法的參數(shù)是一個(gè)Promise對(duì)象的實(shí)例,則會(huì)返回該P(yáng)romise實(shí)例。

Promise.reject

Promise.reject(reason)方法與resolve方法類似,也會(huì)返回一個(gè)新的Promise實(shí)例,但該實(shí)例的狀態(tài)為rejected。Promise.reject方法的參數(shù),會(huì)被傳遞給實(shí)例的回調(diào)函數(shù)。

const reject = Promise.reject('promise reject');
reject.then(null, (err) => {
  console.log(err)
});

輸出結(jié)果:
promise reject

Promise.all

Promise.all方法用于將多個(gè)Promise實(shí)例,包裝成一個(gè)新的Promise實(shí)例,該方法一般接受一個(gè)數(shù)組作為參數(shù),但不一定是數(shù)組,只要具有iterator接口。且返回的每個(gè)成員都是Promise實(shí)例。

const getRandom = () => +(Math.random()*1000).toFixed(0);
const ajax = (taskID) => new Promise(resolve => {
    let timeout = getRandom();
    console.log(`taskID=${taskID} start.`);
    setTimeout(function() {
        console.log(`taskID=${taskID} finished in time=${timeout}.`);
        resolve(taskID)
    }, timeout);
});

Promise.all([ajax(1),ajax(2),ajax(3)])
.then(resultList => {
    console.log('results:',resultList);
});

輸出結(jié)果:
taskID=1 start.
taskID=2 start.
taskID=3 start.
taskID=2 finished in time=27.
taskID=3 finished in time=257.
taskID=1 finished in time=876.
results: [1, 2, 3]

Promise.all狀態(tài)分為兩種:

  • 只有ajax(1)、ajax(2)、ajax(3)的狀態(tài)都變成fulfilled,返回的狀態(tài)才會(huì)變成fulfilled,此時(shí)ajax(1)、ajax(2)、ajax(3)的返回值組成一個(gè)數(shù)組,傳遞給Promise.all的回調(diào)函數(shù)。
  • 只要ajax(1)、ajax(2)、ajax(3)之中有一個(gè)是rejected,返回的狀態(tài)就變成rejected,此時(shí)第一個(gè)被reject的實(shí)例的返回值,會(huì)傳遞給Promise.all的回調(diào)函數(shù)。

Promise.race

Promise.race方法也是將多個(gè)Promise實(shí)例,包裝成一個(gè)新的Promise實(shí)例,與Promise.all不同的是一旦有狀態(tài)改變,就會(huì)返回第一個(gè)狀態(tài)改變的Promise實(shí)例返回值。

const getRandom = () => +(Math.random()*1000).toFixed(0);
const ajax = (taskID) => new Promise(resolve => {
    let timeout = getRandom();
    console.log(`taskID=${taskID} start.`);
    setTimeout(function() {
        console.log(`taskID=${taskID} finished in time=${timeout}.`);
        resolve(taskID)
    }, timeout);
});

Promise.race([ajax(1),ajax(2),ajax(3)])
.then(result => {
    console.log('results:',result);
});

輸出結(jié)果:
taskID=1 start.
taskID=2 start.
taskID=3 start.
taskID=2 finished in time=59.
results: 2
taskID=3 finished in time=707.
taskID=1 finished in time=854.

Promise.race雖然返回第一個(gè)狀態(tài)改變的Promise實(shí)例,但不能阻止其他Promise實(shí)例狀態(tài)改變。

如果Promise.all方法和Promise.race方法的參數(shù),不是Promise實(shí)例,就會(huì)調(diào)用Promise.resolve方法,將參數(shù)轉(zhuǎn)為Promise實(shí)例,再進(jìn)一步處理。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Promise 對(duì)象 Promise 的含義 Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函...
    neromous閱讀 8,839評(píng)論 1 56
  • Promise的含義: ??Promise是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和...
    呼呼哥閱讀 2,282評(píng)論 0 16
  • 目錄:Promise 的含義基本用法Promise.prototype.then()Promise.prototy...
    BluesCurry閱讀 1,575評(píng)論 0 8
  • 00、前言Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強(qiáng)大。它由社區(qū)...
    夜幕小草閱讀 2,230評(píng)論 0 12
  • Promiese 簡(jiǎn)單說(shuō)就是一個(gè)容器,里面保存著某個(gè)未來(lái)才會(huì)結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果,語(yǔ)法上說(shuō),Pr...
    雨飛飛雨閱讀 3,494評(píng)論 0 19

友情鏈接更多精彩內(nèi)容