<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>

          【JS】881- 我終于弄懂了Promise

          共 12194字,需瀏覽 25分鐘

           ·

          2021-02-28 08:55


          轉(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="font-size: 14px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">resolved和從pending變?yōu)?code style="font-size: 14px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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="font-size: 14px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">resolved,將異步操作的結(jié)果,作為參數(shù)傳遞出去
          • reject——將Promise對(duì)象的狀態(tài)從pending變?yōu)?code style="font-size: 14px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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="font-size: 14px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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="font-size: 14px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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 = {
            thenfunction(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="font-size: 14px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;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([123]);
          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 的源碼



          1. JavaScript 重溫系列(22篇全)
          2. ECMAScript 重溫系列(10篇全)
          3. JavaScript設(shè)計(jì)模式 重溫系列(9篇全)
          4. 正則 / 框架 / 算法等 重溫系列(16篇全)
          5. Webpack4 入門(上)|| Webpack4 入門(下)
          6. MobX 入門(上) ||  MobX 入門(下)
          7. 100+篇原創(chuàng)系列匯總

          回復(fù)“加群”與大佬們一起交流學(xué)習(xí)~

          點(diǎn)擊“閱讀原文”查看 100+ 篇原創(chuàng)文章

          瀏覽 44
          點(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>
                  黄色影院在线免费观看 | 色av婷婷 | 日本乱伦一区二区三区 | 777免费视频 | 丁香激情五月天 |