Promise的使用

1、Promise的使用

1.1 前期

在Promise出現(xiàn)之前,我們?nèi)绾卧诎l(fā)送網(wǎng)絡(luò)請(qǐng)求后對(duì)響應(yīng)的結(jié)果進(jìn)行處理呢?

function requestUrl(url, success, failure) {
  setTimeout(() => {
    if (url == "true url") {
      success("result");
    } else {
      failure("error");
    }
  }, 50);
}

此時(shí),我們通常會(huì)借助回調(diào)函數(shù),如代碼中的 successfailure就對(duì)應(yīng)著響應(yīng)成功和失敗時(shí)調(diào)用的回調(diào)函數(shù),使用如上方案可以解決請(qǐng)求函數(shù)得到結(jié)果之后,獲取到對(duì)應(yīng)的回調(diào),但是它存在兩個(gè)主要的問題:

  • 我們需要自己來設(shè)計(jì)回調(diào)函數(shù)、回調(diào)函數(shù)的名稱、回調(diào)函數(shù)的使用等;
  • 對(duì)于不同的人、不同的框架設(shè)計(jì)出來的方案是不同的,那么我們必須耐心去看別人的源碼或者文檔,以便可以理解它這個(gè)函數(shù)到底怎么用;

1.2 Promise的出現(xiàn)

Promise是一個(gè)類,可以翻譯成 承諾、許諾 、期約;

  • 當(dāng)我們需要給予調(diào)用者一個(gè)承諾:待會(huì)兒我會(huì)給你回調(diào)數(shù)據(jù)時(shí),就可以創(chuàng)建一個(gè)Promise的對(duì)象;
  • 在通過new創(chuàng)建Promise對(duì)象時(shí),我們需要傳入一個(gè)回調(diào)函數(shù),我們稱之為executor
    這個(gè)回調(diào)函數(shù)會(huì)被立即執(zhí)行,并且接受另外兩個(gè)回調(diào)函數(shù)resolve、reject作為參數(shù);
    當(dāng)我們調(diào)用resolve回調(diào)函數(shù)時(shí),會(huì)執(zhí)行Promise對(duì)象的then方法傳入的回調(diào)函數(shù);
    當(dāng)我們調(diào)用reject回調(diào)函數(shù)時(shí),會(huì)執(zhí)行Promise對(duì)象的catch方法傳入的回調(diào)函數(shù);

Promise的結(jié)構(gòu)

const promise = new Promise((resolve, reject) => {
  resolve("success");
  reject("error");
});

promise
  .then(() => {
    console.log(res); //result
  })
  .catch((err) => {
    console.log(err); //error
  });

我們可以將Promise劃分成三個(gè)狀態(tài):

  • 待定(pending): 初始狀態(tài),既沒有被兌現(xiàn),也沒有被拒絕;
    當(dāng)執(zhí)行executor中的代碼時(shí),處于該狀態(tài);
  • 已兌現(xiàn)(fulfilled): 意味著操作成功完成;
    執(zhí)行了resolve時(shí),處于該狀態(tài);
  • 已拒絕(rejected): 意味著操作失敗;
    執(zhí)行了reject時(shí),處于該狀態(tài);

1.3 Promise重構(gòu)

function requestUrl(url) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (url == "true url") {
        resolve("success");
      } else {
        reject("error");
      }
    }, 50);
  });
}

2、Promise詳解

2.1 Executor

Executor是在創(chuàng)建Promise時(shí)需要傳入的一個(gè)回調(diào)函數(shù),這個(gè)回調(diào)函數(shù)會(huì)被立即執(zhí)行,并且接受兩個(gè)函數(shù)作為參數(shù):

new Promise((resolve, reject) => {
  
})

通常我們會(huì)在Executor中確定我們的Promise狀態(tài):

  • 通過resolve,可以兌現(xiàn)(fulfilled)Promise的狀態(tài),我們也可以稱之為已決議(resolved);
  • 通過reject,可以拒絕(reject)Promise的狀態(tài);

一旦狀態(tài)被確定下來,Promise的狀態(tài)會(huì)被 鎖死,該P(yáng)romise的狀態(tài)是不可更改的
在我們調(diào)用resolve的時(shí)候,如果resolve傳入的值本身不是一個(gè)Promise,那么會(huì)將該P(yáng)romise的狀態(tài)變成 兌現(xiàn)(fulfilled);
在之后我們?nèi)フ{(diào)用reject時(shí),已經(jīng)不會(huì)有任何的響應(yīng)了(并不是這行代碼不會(huì)執(zhí)行,而是無法改變Promise狀態(tài));

2.2 resolve不同值的區(qū)別

  • 情況一:如果resolve傳入一個(gè)普通的值或者對(duì)象,那么這個(gè)值會(huì)作為then回調(diào)的參數(shù);
  • 情況二:如果resolve中傳入的是另外一個(gè)Promise,那么這個(gè)新Promise會(huì)決定原Promise的狀態(tài):
  • 情況三:如果resolve中傳入的是一個(gè)對(duì)象,并且這個(gè)對(duì)象有實(shí)現(xiàn)then方法,那么會(huì)執(zhí)行該then方法,并且根據(jù)
    then方法的結(jié)果來決定Promise的狀態(tài):
image.png

2.3 then方法

  • then方法是Promise對(duì)象上的一個(gè)方法:它其實(shí)是放在Promise的原型上的 Promise.prototype.then
    then方法接受兩個(gè)參數(shù):
    fulfilled的回調(diào)函數(shù):當(dāng)狀態(tài)變成fulfilled時(shí)會(huì)回調(diào)的函數(shù);
    reject的回調(diào)函數(shù):當(dāng)狀態(tài)變成reject時(shí)會(huì)回調(diào)的函數(shù);
image.png
  • 一個(gè)Promise的then方法是可以被多次調(diào)用的:
    每次調(diào)用我們都可以傳入對(duì)應(yīng)的fulfilled回調(diào);
    當(dāng)Promise的狀態(tài)變成fulfilled的時(shí)候,這些回調(diào)函數(shù)都會(huì)被執(zhí)行;


    image.png
  • then方法本身是有返回值的,它的返回值是一個(gè)Promise,所以我們可以進(jìn)行如下的鏈?zhǔn)秸{(diào)用,then方法返回的Promise到底處于什么樣的狀態(tài)呢?
    Promise有三種狀態(tài),那么這個(gè)Promise處于什么狀態(tài)呢?
    a、當(dāng)then方法中的回調(diào)函數(shù)本身在執(zhí)行的時(shí)候,那么它處于pending狀態(tài);
    b、當(dāng)then方法中的回調(diào)函數(shù)返回一個(gè)結(jié)果時(shí),那么它處于fulfilled狀態(tài),并且會(huì)將結(jié)果作為resolve的參數(shù);
    情況一:返回一個(gè)普通的值;
    情況二:返回一個(gè)Promise;
    情況三:返回一個(gè)thenable值;
    c、當(dāng)then方法拋出一個(gè)異常時(shí),那么它處于reject狀態(tài);

2.4 catch方法

  • catch方法也是Promise對(duì)象上的一個(gè)方法:它也是放在Promise的原型上的 Promise.prototype.catch

  • 一個(gè)Promise的catch方法是可以被多次調(diào)用的:
    每次調(diào)用我們都可以傳入對(duì)應(yīng)的reject回調(diào);
    當(dāng)Promise的狀態(tài)變成reject的時(shí)候,這些回調(diào)函數(shù)都會(huì)被執(zhí)行


    image.png
  • 返回值:catch方法也是會(huì)返回一個(gè)Promise對(duì)象的,所以catch方法后面我們可以繼續(xù)調(diào)用then方法或者catch方法

2.5 finally方法

finally是在ES9(ES2018)中新增的一個(gè)特性:表示無論P(yáng)romise對(duì)象無論變成fulfilled還是reject狀態(tài),最終都會(huì)被執(zhí)行的代碼。
finally方法是不接收參數(shù)的,因?yàn)闊o論前面是fulfilled狀態(tài),還是reject狀態(tài),它都會(huì)執(zhí)行。


image.png

2.6 resolve方法

有時(shí)候我們已經(jīng)有一個(gè)現(xiàn)成的內(nèi)容了,希望將其轉(zhuǎn)成Promise來使用,這個(gè)時(shí)候我們可以使用 Promise.resolve 方法來完成。

  • Promise.resolve的用法相當(dāng)于new Promise,并且執(zhí)行resolve操作


    image.png
  • resolve參數(shù)的形態(tài):
    情況一:參數(shù)是一個(gè)普通的值或者對(duì)象
    情況二:參數(shù)本身是Promise
    情況三:參數(shù)是一個(gè)thenable

2.7 reject方法

reject方法類似于resolve方法,只是會(huì)將Promise對(duì)象的狀態(tài)設(shè)置為reject狀態(tài)。
Promise.reject的用法相當(dāng)于new Promise,只是會(huì)調(diào)用reject:
Promise.reject傳入的參數(shù)無論是什么形態(tài),都會(huì)直接作為reject狀態(tài)的參數(shù)傳遞到catch的。

2.8 all方法

  • 將多個(gè)Promise包裹在一起形成一個(gè)新的Promise;新的Promise狀態(tài)由包裹的所有Promise共同決定:
  • 當(dāng)所有的Promise狀態(tài)變成fulfilled狀態(tài)時(shí),新的Promise狀態(tài)為fulfilled,并且會(huì)將所有Promise的返回值
    組成一個(gè)數(shù)組;
  • 當(dāng)有一個(gè)Promise狀態(tài)為reject時(shí),新的Promise狀態(tài)為reject,并且會(huì)將第一個(gè)reject的返回值作為參數(shù);
image.png

2.9 allSettled方法

  • all方法有一個(gè)缺陷:當(dāng)有其中一個(gè)Promise變成reject狀態(tài)時(shí),新Promise就會(huì)立即變成對(duì)應(yīng)的reject狀態(tài)。
    那么對(duì)于resolved的,以及依然處于pending狀態(tài)的Promise,我們是獲取不到對(duì)應(yīng)的結(jié)果的;
  • 在ES11(ES2020)中,添加了新的API Promise.allSettled:
    該方法會(huì)在所有的Promise都有結(jié)果(settled),無論是fulfilled,還是reject時(shí),才會(huì)有最終的狀態(tài);
    并且這個(gè)Promise的結(jié)果一定是fulfilled的;


    image.png

    打印的結(jié)果為


    image.png

2.10 race方法

如果有一個(gè)Promise有了結(jié)果,我們就希望決定最終新Promise的狀態(tài),那么可以使用race方法:
race是競(jìng)技、競(jìng)賽的意思,表示多個(gè)Promise相互競(jìng)爭(zhēng),誰(shuí)先有結(jié)果,那么就使用誰(shuí)的結(jié)果;


image.png

2.11 any方法(至少有一個(gè)resolve)

any方法是ES12中新增的方法,和race方法是類似的:
pany方法會(huì)等到一個(gè)fulfilled狀態(tài),才會(huì)決定新Promise的狀態(tài);
如果所有的Promise都是reject的,那么也會(huì)等到所有的Promise都變成rejected狀態(tài);


image.png

如果所有的Promise都是reject的,那么會(huì)報(bào)一個(gè)AggregateError的錯(cuò)誤。

最后編輯于
?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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