<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          我終于弄懂了Promise

          共 8844字,需瀏覽 18分鐘

           ·

          2021-02-19 16:57

          轉(zhuǎn)自:掘金 -?前端布吉島

          https://juejin.cn/post/6921593620680802311

          寫在前面

          以前總是似懂非懂,這次總算把它弄了個(gè)清楚

          什么是Promise

          • ES6 異步編程的一種解決方案,比傳統(tǒng)的方案(回調(diào)函數(shù)和事件)更加的合理和強(qiáng)大
          • 好處 異步操作以同步操作的流程表達(dá)出來,避免了層層嵌套的回調(diào)函數(shù)
          • promise可以解決異步的問題,本身不能說promise是異步的

          Promise特點(diǎn)

          • 對(duì)象的狀態(tài)不受外界影響Promise對(duì)象代表一個(gè)異步操作,有三種狀態(tài):pending(進(jìn)行中)、resolved(已成功)和rejected(已失敗)
          • 一旦狀態(tài)改變,就不會(huì)再變,任何時(shí)候都可以得到這個(gè)結(jié)果Promise對(duì)象的狀態(tài)改變,只有兩種可能:從pending變?yōu)?code style="margin: 0px 2px;padding: 2px 4px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;font-size: 14px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;overflow-wrap: break-word;border-radius: 4px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">resolved和從pending變?yōu)?code style="margin: 0px 2px;padding: 2px 4px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;font-size: 14px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;overflow-wrap: break-word;border-radius: 4px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">rejected
          • promise內(nèi)部發(fā)生錯(cuò)誤,不會(huì)影響到外部程序的執(zhí)行。
          • 無法取消Promise。一旦新建它就會(huì)立即執(zhí)行,無法中途取消。其次,如果不設(shè)置回調(diào)函數(shù),Promise內(nèi)部拋出的錯(cuò)誤,不會(huì)反應(yīng)到外部。第三,當(dāng)處于pending狀態(tài)時(shí),無法得知目前進(jìn)展到哪一個(gè)階段(剛剛開始還是即將完成)

          用法

          基礎(chǔ)用法

          創(chuàng)造Promise實(shí)例時(shí),必須傳入一個(gè)函數(shù)作為參數(shù)

          new?Promise(()?=>?{});
          new?Promise();?//?報(bào)錯(cuò)


          該函數(shù)可以接收另外兩個(gè)由JavaScript引擎提供的函數(shù),resolvereject。函數(shù)作用:

          • resolve——將Promise對(duì)象的狀態(tài)從pending變?yōu)?code style="margin: 0px 2px;padding: 2px 4px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;font-size: 14px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;overflow-wrap: break-word;border-radius: 4px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">resolved,將異步操作的結(jié)果,作為參數(shù)傳遞出去
          • reject——將Promise對(duì)象的狀態(tài)從pending變?yōu)?code style="margin: 0px 2px;padding: 2px 4px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;font-size: 14px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;overflow-wrap: break-word;border-radius: 4px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">rejected,將異步操作報(bào)出的錯(cuò)誤,作為參數(shù)傳遞出去
          let?promise?=?new?Promise((resolve,?reject)?=>?{
          ??//?do?something
          ??if?(true)?{
          ????//?將參數(shù)返回,供then方法使用
          ????resolve("value");
          ??}?else?{
          ????//?將參數(shù)返回,供then方法使用
          ????reject("error");
          ??}
          });


          Promise實(shí)例生成以后,可以用then方法分別指定resolved狀態(tài)和rejected狀態(tài)的回調(diào)函數(shù)。

          promise.then(
          ??value?=>?{
          ????//?resolved時(shí)調(diào)用,value為resolve函數(shù)返回的參數(shù)
          ????console.log(value);
          ??},
          ??err?=>?{
          ????//?rejected時(shí)調(diào)用,err為reject函數(shù)返回的參數(shù)
          ????console.log(err);
          ??}
          );


          當(dāng)then方法只有一個(gè)函數(shù)參數(shù)時(shí),此時(shí)為resolved狀態(tài)的回調(diào)方法

          promise.then(value?=>?{
          ????//?只有狀態(tài)為resolved時(shí)才能調(diào)用,如果返回的是rejected狀態(tài),則報(bào)錯(cuò)?Uncaught?(in?promise)?error
          ????console.log(value);
          ??});


          只有當(dāng)promise的狀態(tài)變?yōu)閞esolved或者rejected時(shí),then方法才會(huì)被調(diào)用

          Promise 新建后就會(huì)立即執(zhí)行,并且調(diào)用resolvereject后不會(huì)終結(jié)?Promise的參數(shù)函數(shù)的執(zhí)行。

          let?promise?=?new?Promise(function(resolve)?{
          ??console.log("Promise");
          ??resolve();
          ??console.log("!!!")
          });

          promise.then(function()?{
          ??console.log("resolved.");
          });
          console.log("Hi!");

          //?Promise
          //?!!!
          //?Hi!
          //?resolved


          resolve返回的是另外一個(gè)Promise實(shí)例

          const?p1?=?new?Promise((_,?reject)?=>?{
          ??setTimeout(()?=>?reject('error'),?3000);
          });

          const?p2?=?new?Promise(resolve?=>?{
          ??setTimeout(()?=>?resolve(p1),?1000);
          });

          p2.then(
          ??result?=>?console.log(result),
          ??error?=>?console.log(error)?//?error
          );


          上面代碼中,p1是一個(gè)?Promise,3 秒之后變?yōu)?code style="margin: 0px 2px;padding: 2px 4px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;font-size: 14px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;overflow-wrap: break-word;border-radius: 4px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">rejected。p2的狀態(tài)在 1 秒之后改變,resolve方法返回的是p1。由于p2返回的是另一個(gè) Promise,導(dǎo)致p2自己的狀態(tài)無效了,由p1的狀態(tài)決定p2的狀態(tài)。所以,后面的then語句都變成針對(duì)后者(p1)。又過了 2 秒,p1變?yōu)?code style="margin: 0px 2px;padding: 2px 4px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;font-size: 14px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;overflow-wrap: break-word;border-radius: 4px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">rejected,導(dǎo)致觸發(fā)catch方法指定的回調(diào)函數(shù)。

          以上是原文解釋,我們可以理解成p2.then?實(shí)際上是p1.then

          Promise.prototype.then()

          then方法是定義在原型對(duì)象Promise.prototype上的,同時(shí)then方法的兩個(gè)參數(shù)都是非必選的。因?yàn)閠hen方法返回的是一個(gè)**全新**的promise實(shí)例時(shí),因此then方法可以鏈?zhǔn)秸{(diào)用?then方法在以下情況返回的promise

          1. 當(dāng)未傳入?yún)?shù)時(shí),then方法會(huì)返回一個(gè)新的,狀態(tài)和原promise相同的promise
          const?promise?=?new?Promise(resolve?=>?{
          ??resolve("resolve");
          });

          let?p?=?promise.then();
          console.log(promise);
          console.log(p);


          結(jié)果展示

          1. 上一個(gè)promise未被成功調(diào)用then方法時(shí),返回的結(jié)果如情形1
          const?promise?=?new?Promise((_,?reject)?=>?{
          ??reject("reject");
          });
          let?a?=?promise.then(value?=>?{
          ??console.log(value);
          });


          1. 上一個(gè)promise被成功調(diào)用then方法時(shí),返回一個(gè)`resolve(undefined)`的promise
          const?promise?=?new?Promise((_,?reject)?=>?{
          ??reject("reject");
          });
          let?a?=?promise.then(undefined,?value?=>?{
          ??console.log(value);
          });
          console.log(a);


          1. 上一個(gè)promise被成功調(diào)用then方法,但出現(xiàn)報(bào)錯(cuò),返回一個(gè)`reject('error')`的promise,`error`代指錯(cuò)誤,并非真正的`reject`返回的結(jié)果
          const?promise?=?new?Promise(resolve?=>?{
          ??resolve("resolve");
          });

          let?p?=?promise.then(value?=>?{
          ??console.log(value);
          ??throw?new?Error("fail1");
          });
          console.log(p);


          結(jié)果展示:

          1. 給then方法手動(dòng)返回一個(gè)promise,此時(shí)會(huì)覆蓋掉默認(rèn)的行為,返回值為新增的promise
          const?promise?=?new?Promise(resolve?=>?{
          ??resolve("resolve");
          });

          let?p?=?promise.then(
          ??()?=>
          ??new?Promise(resolve?=>?{
          ????resolve("resolve2");
          ??})
          );
          console.log(p);


          Promise.prototype.catch()

          catch()方法是.then(null, rejection).then(undefined, rejection)的別名,用于指定發(fā)生錯(cuò)誤時(shí)的回調(diào)函數(shù)。

          const?promise?=?new?Promise((_,?reject)?=>?{
          ??reject("reject");
          });

          promise
          ??.then(value?=>?{
          ??console.log(value);
          })
          ?//?發(fā)生錯(cuò)誤,或者reject時(shí)執(zhí)行
          ??.catch(value?=>?{
          ??console.log(value);
          });


          如果 Promise 狀態(tài)已經(jīng)變成resolved,再拋出錯(cuò)誤是無效的。

          const?promise?=?new?Promise(resolve?=>?{
          ??resolve("resolve");
          ??throw?new?Error("fail");
          });

          promise.then(value?=>?console.log(value));


          promise中所有沒有被處理的錯(cuò)誤都會(huì)冒泡到最后一個(gè)catch中

          const?promise?=?new?Promise(resolve?=>?{
          ??resolve("resolve");
          });
          promise
          ??.then(value?=>?{
          ??console.log(value);
          ??throw?new?Error("fail1");
          })
          ??.then(()?=>?{
          ??throw?new?Error("fail2");
          })
          ??.catch(value?=>?{
          ??console.log(value);
          });


          在上面的代碼中,catch會(huì)優(yōu)先打印打印第一個(gè)錯(cuò)誤,當(dāng)?shù)谝粋€(gè)錯(cuò)誤解決之后(注釋掉就ok),catch里才會(huì)打印第二個(gè)錯(cuò)誤?catch的返回值仍是promise,返回promise的方式和then相似,因此,catch后仍然可以調(diào)用then方法

          Promise.prototype.finally()

          finally()方法用于指定不管 Promise 對(duì)象最后狀態(tài)如何,都會(huì)執(zhí)行的操作。finally方法的回調(diào)函數(shù)不接受任何參數(shù),這表明,finally方法里面的操作,應(yīng)該是與狀態(tài)無關(guān)的,不依賴于 Promise 的執(zhí)行結(jié)果。

          const?promise?=?new?Promise(resolve?=>?{
          ??resolve("resolve");
          });
          promise.finally(()?=>?{
          ??console.log(11);?//?11
          });


          finally的本質(zhì)

          promise.finally(()?=>?{
          ??//?do?something
          });

          //?等同于
          promise.then(
          ??result?=>?{
          ????//?do?something
          ????return?result;
          ??},
          ??error?=>?{
          ????//?do?something
          ????throw?error;
          ??}
          );


          finally的返回值為一個(gè)新的和原來的值相似的promise

          Promise.resolve()

          有時(shí)需要將現(xiàn)有對(duì)象轉(zhuǎn)為 Promise 對(duì)象,Promise.resolve()方法就起到這個(gè)作用,且實(shí)例狀態(tài)為resolve

          Promise.resolve('foo')
          //?等價(jià)于
          new?Promise(resolve?=>?resolve('foo'))


          Promise.resolve()方法的參數(shù)分成四種情況

          參數(shù)是一個(gè) Promise 實(shí)例

          const?promise?=?new?Promise(resolve?=>?{
          ??resolve("resolve");
          });
          let?p?=?Promise.resolve(promise);
          console.log(p?==?promise);?//?true


          參數(shù)是一個(gè)thenable對(duì)象

          thenable對(duì)象指的是具有then方法的對(duì)象,Promise.resolve()方法會(huì)將這個(gè)對(duì)象轉(zhuǎn)為 Promise 對(duì)象,然后就立即執(zhí)行thenable對(duì)象的then()方法

          //?thenable對(duì)象
          let?thenable?=?{
          ??then:?function(resolve,?reject)?{
          ????resolve(42);
          ??}
          };

          let?p1?=?Promise.resolve(thenable);
          p1.then(function?(value)?{
          ??console.log(value);??//?42
          });


          上面代碼中,thenable對(duì)象的then()方法執(zhí)行后,對(duì)象p1的狀態(tài)就變?yōu)?code style="margin: 0px 2px;padding: 2px 4px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;font-size: 14px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;overflow-wrap: break-word;border-radius: 4px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">resolved,從而立即執(zhí)行最后那個(gè)then()方法指定的回調(diào)函數(shù),輸出42

          參數(shù)不是具有then()方法的對(duì)象,或根本就不是對(duì)象

          const?p?=?Promise.resolve('Hello');
          p.then(function?(s)?{
          ??console.log(s)?//?Hello
          });


          不帶有任何參數(shù)

          Promise.resolve()方法允許調(diào)用時(shí)不帶參數(shù),直接返回一個(gè)resolved狀態(tài)的 Promise 對(duì)象

          Promise.resolve();
          //?相當(dāng)于
          new?Promise(resolve?=>?resolve(undefined))


          Promise.reject()

          Promise.reject(reason)方法也會(huì)返回一個(gè)新的 Promise 實(shí)例,該實(shí)例的狀態(tài)為rejected

          const?p?=?Promise.reject('出錯(cuò)了');
          //?等同于
          const?p?=?new?Promise((resolve,?reject)?=>?reject('出錯(cuò)了'))


          Promise.all()

          Promise.all()方法用于將多個(gè) Promise 實(shí)例,包裝成一個(gè)新的 Promise 實(shí)例

          const?p?=?Promise.all([p1,?p2,?p3]);


          面代碼中,Promise.all()方法接受一個(gè)數(shù)組作為參數(shù),p1p2p3都是 Promise 實(shí)例,如果不是,就會(huì)調(diào)用Promise.resolve方法,將參數(shù)轉(zhuǎn)為 Promise 實(shí)例,再進(jìn)一步處理。另外,Promise.all()方法的參數(shù)可以不是數(shù)組,但必須具有 Iterator 接口,且返回的每個(gè)成員都是 Promise 實(shí)例。p的狀態(tài)由p1p2p3決定,分成兩種情況。

          • 只有p1p2p3的狀態(tài)都變成fulfilledp的狀態(tài)才會(huì)變成fulfilled,此時(shí)p1p2p3的返回值組成一個(gè)數(shù)組,傳遞給p的回調(diào)函數(shù)。
          • 只要p1p2p3之中有一個(gè)被rejectedp的狀態(tài)就變成rejected,此時(shí)第一個(gè)被reject的實(shí)例的返回值,會(huì)傳遞給p的回調(diào)函數(shù)。
          let?promise?=?Promise.all([1,?2,?3]);
          promise.then(value?=>?{
          ??console.log(value);?//?[1,2,3]
          });
          console.log(promise);


          情形一promise結(jié)果:

          let?p2?=?Promise.reject(2);
          let?promise?=?Promise.all([1,?p2,?3]);
          promise
          ??.then(value?=>?{
          ??console.log(value);
          })
          ??.catch(err?=>?{
          ??console.log(err);?//?2
          });
          console.log(promise);


          情形二promise結(jié)果:
          如果作為參數(shù)的 Promise 實(shí)例,自己定義了catch方法,那么它一旦被rejected,并不會(huì)觸發(fā)Promise.all()catch方法

          const?p1?=?new?Promise(resolve?=>?{
          ??resolve("hello");
          })
          .then(result?=>?result)
          .catch(e?=>?e);

          const?p2?=?new?Promise(()?=>?{
          ??throw?new?Error("報(bào)錯(cuò)了");
          })
          .then(result?=>?result)
          .catch(e?=>?e);?//?p2實(shí)際上是catch返回的promise實(shí)例
          Promise.all([p1,?p2])
          ??.then(result?=>?console.log(result))
          ??.catch(e?=>?console.log(e));


          Promise.race()

          Promise.race()方法同樣是將多個(gè) Promise 實(shí)例,包裝成一個(gè)新的 Promise 實(shí)例。Promise.race()方法的參數(shù)與Promise.all()方法一樣,如果不是 Promise 實(shí)例,就會(huì)先調(diào)用下面講到的Promise.resolve()方法,將參數(shù)轉(zhuǎn)為 Promise 實(shí)例,再進(jìn)一步處理。

          const?p?=?Promise.race([p1,?p2,?p3]);


          上面代碼中,只要p1p2p3之中有一個(gè)實(shí)例率先改變狀態(tài),p的狀態(tài)就跟著改變。那個(gè)率先改變的 Promise 實(shí)例的返回值,就傳遞給p的回調(diào)函數(shù)。

          Promise.allSettled()

          Promise.allSettled()方法接受一組 Promise 實(shí)例作為參數(shù),包裝成一個(gè)新的 Promise 實(shí)例。只有等到所有這些參數(shù)實(shí)例都返回結(jié)果,不管是fulfilled還是rejected,包裝實(shí)例才會(huì)結(jié)束,參數(shù)與Promise.all()方法一樣

          let?p2?=?Promise.reject(2);
          let?promise?=?Promise.allSettled([1,?p2,?3]);
          promise.then(value?=>?{
          ??console.log(value);?//?[{status:?"fulfilled",?value:?1},{status:?"rejected",?reason:?2},{status:?"fulfilled",?value:?3}]
          });
          console.log(promise);


          Promise.allSettled()的返回的promise實(shí)例狀態(tài)只可能變成resolved,它的監(jiān)聽函數(shù)收到的參數(shù)是一個(gè)數(shù)組,該數(shù)組的每個(gè)成員都是一個(gè)對(duì)象,每一個(gè)對(duì)象都有status屬性,該屬性的值只可能是字符串fulfilled或字符串rejectedfulfilled時(shí),對(duì)象有value屬性,rejected時(shí)有reason屬性,對(duì)應(yīng)兩種狀態(tài)的返回值。

          Promise.any()

          該方法接受一組 Promise 實(shí)例作為參數(shù),包裝成一個(gè)新的 Promise 實(shí)例返回。只要參數(shù)實(shí)例有一個(gè)變成fulfilled狀態(tài),包裝實(shí)例就會(huì)變成fulfilled狀態(tài);如果所有參數(shù)實(shí)例都變成rejected狀態(tài),包裝實(shí)例就會(huì)變成rejected狀態(tài)。Promise.any()Promise.race()方法很像,只有一點(diǎn)不同,就是不會(huì)因?yàn)槟硞€(gè) Promise 變成rejected狀態(tài)而結(jié)束。

          let?p1?=?Promise.reject(1);
          let?p2?=?Promise.reject(2);
          let?promise?=?Promise.any([p1,?p2,?3]);
          promise.then(value?=>?{
          ??console.log(value);?//?3
          });
          console.log(promise);


          當(dāng)所有的實(shí)例返回的狀態(tài)都是rejected時(shí),Promise.any()會(huì)返回一個(gè)的實(shí)例狀態(tài)才為rejected

          let?p1?=?Promise.reject(1);
          let?p2?=?Promise.reject(2);
          let?promise?=?Promise.any([p1,?p2]);
          promise
          ??.then(value?=>?{
          ??console.log(value);
          })
          ??.catch(value?=>?{
          ??console.log(value);?//?AggregateError:?All?promises?were?rejected
          });
          console.log(promise);


          Promise.try()

          實(shí)際開發(fā)中,經(jīng)常遇到一種情況:不知道或者不想?yún)^(qū)分,函數(shù)f是同步函數(shù)還是異步操作,但是想用 Promise 來處理它。因?yàn)檫@樣就可以不管f是否包含異步操作,都用then方法指定下一步流程,用catch方法處理f拋出的錯(cuò)誤。一般就會(huì)采用下面的寫法。

          const?f?=?()?=>?console.log('now');
          Promise.resolve().then(f);
          console.log('next');
          //?next
          //?now


          上面的寫法有一個(gè)缺點(diǎn),就是如果f是同步函數(shù),那么它會(huì)在本輪事件循環(huán)的末尾執(zhí)行。鑒于這是一個(gè)很常見的需求,所以現(xiàn)在有一個(gè)提案,提供Promise.try方法替代上面的寫法。

          const?f?=?()?=>?console.log('now');
          Promise.try(f);
          console.log('next');
          //?now
          //?next
          帶你寫出符合 Promise/A+ 規(guī)范 Promise 的源碼


          瀏覽 67
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  а√中文在线资源库 | 小黄片免费看 | 爱爱图片一级 | 国产精品秘 久久久久久电影院 | 爱爱视频在线看 |