2025-08-05 Promise

一、基礎(chǔ)鞏固

1.實例對象和函數(shù)對象

(1)普通對象都是實例對象,即由 new關(guān)鍵字 創(chuàng)建出來的對象。
(2)函數(shù)本身也是對象,具體體現(xiàn)為 將函數(shù)當做對象來使用。
(3)括號前面是函數(shù),點前面是對象。

      function Fn(){}  //Fn是函數(shù)
      const fn = new Fn() //Fn是構(gòu)造函數(shù),fn是構(gòu)造函數(shù)的實例對象
      console.log(Fn.prototype);//將Fn函數(shù)當做對象使用,所以Fn是函數(shù)對象

      $('#app') //$代表jquery函數(shù)
      $.get() // 發(fā)送ajax請求時將$函數(shù)當做對象使用,所以$是函數(shù)對象。
2.兩種類型的回調(diào)函數(shù)

(1)回調(diào)函數(shù)可以理解為 自己定義,但不是由自己調(diào)用的函數(shù)
(2)同步回調(diào)函數(shù):立即執(zhí)行的回調(diào)函數(shù),結(jié)束后再執(zhí)行后面的內(nèi)容。不會加入異步回調(diào)隊列。

// 1.同步回調(diào)函數(shù):立即執(zhí)行的回調(diào)函數(shù),結(jié)束后再執(zhí)行后面的內(nèi)容。不會加入異步回調(diào)隊列。
// 例如:數(shù)組遍歷相關(guān)的回調(diào)函數(shù) || Promise的excutor函數(shù)
const arr = [1, 2, 3];
arr.forEach((item) => {
    console.log(item);
});
console.log('遍歷后面的內(nèi)容執(zhí)行');

(3)異步回調(diào)函數(shù):回調(diào)函數(shù)不會立即執(zhí)行,會放入回調(diào)隊列在將來執(zhí)行。

// 2.異步回調(diào)函數(shù):回調(diào)函數(shù)不會立即執(zhí)行,會放入回調(diào)隊列在將來執(zhí)行。
// 例如:定時器的回調(diào)函數(shù) || Promise的成功或失敗的回調(diào)。
setTimeout(() => {
    console.log('定時器的回調(diào)函數(shù)執(zhí)行');
}, 0);
console.log('定時器后面的內(nèi)容執(zhí)行');
3.錯誤處理

(1)寫函數(shù)時,對可能的錯誤手動拋出,具體處理有調(diào)用者決定。
(2)用 try{ }catch(err){ } 代碼塊包裹可能出現(xiàn)錯誤的代碼,并對錯誤進行捕獲。

            function fn() {
                const num = Math.round(Math.random());
                if (num === 0) {
                    console.log('隨機數(shù)是0');
                } else {
                    throw new Error('隨機數(shù)是1'); //throw error拋出異常,具體的處理有調(diào)用者決定
                }
            }

            //捕獲異常
            try {
                fn();
            } catch (error) {
                alert(error);
            }

二、Promise的理解和使用

1.什么是Promise

抽象表達:
Promise 是 JS 中進行異步編程的新解決方案(舊方案是單純使用回調(diào)函數(shù))

具體表達:
(1)從語法上來說: Promise 是一個 構(gòu)造函數(shù)。
(2)從功能上來說: promise 對象用來封裝一個異步操作并可以獲取其成功/失敗的結(jié)果值。
(3)Promise構(gòu)造函數(shù)(的回調(diào)函數(shù))是同步執(zhí)行的,我們將異步操作放到回調(diào)函數(shù)體內(nèi),成功和失敗時分別調(diào)用resolve和reject函數(shù),這兩個函數(shù)是異步調(diào)用的,且這兩個函數(shù)內(nèi)部會調(diào)用then方法中聲明的成功和失敗的回調(diào)函數(shù)。

2. promise 的狀態(tài)改變

(1) pending 變?yōu)?resolved
(2) pending 變?yōu)?rejected
說明:
① 只有這 2 種情況, 且一個 promise 對象 只能改變一次。
② 無論變?yōu)槌晒€是失敗, 都會有一個結(jié)果數(shù)據(jù)。
③ 成功的結(jié)果數(shù)據(jù)一般稱為 value, 失敗的結(jié)果數(shù)據(jù)一般稱為 reason。

3.Promise 的注意點

(1)Promise構(gòu)造函數(shù)本身是同步執(zhí)行的,它處理的異步操作依然是異步執(zhí)行的,但是可以通過 then()方法 或者 async、await 處理這個異步操作。

   const p1 = new Promise((resolve)=> {
      setTimeout(()=> {
        console.log("定時器結(jié)束"); // 第二
        resolve();
      },1000)
    })
    p1.then(()=> {
      console.log("then代碼"); // 第三
    })
    console.log("普通同步代碼"); // 第一

(2)Promise的 執(zhí)行器函數(shù) 是一個 同步回調(diào)函數(shù),即 new Promise(()=>{}) 時會立即執(zhí)行該回調(diào)函數(shù)。
(3)成功和失敗的回調(diào)是 異步回調(diào)函數(shù)。就是resolve()方法內(nèi)部 異步調(diào)用then()指定的onResolved()回調(diào)函數(shù)。(手寫Promise)
(4)直接掛載到函數(shù)對象上的方法只能被 構(gòu)造函數(shù)使用;掛載到原型對象上的方法由 實例對象使用。

Promise.all() 和 Promise.prototype.then()

三、Promise的API的使用

1.Promise構(gòu)造函數(shù)

格式:Promise (excutor) {}
(1)excutor 執(zhí)行器函數(shù): 同步執(zhí)行的回調(diào)函數(shù) (resolve, reject) => {}
(2)resolve 函數(shù): 內(nèi)部定義成功 時我們要調(diào)用的函數(shù) value => {}
(3)reject 函數(shù): 內(nèi)部定義失敗 時我們要調(diào)用的函數(shù) reason => {}
說明: excutor 會在 Promise 內(nèi)部立即同步回調(diào),異步操作會在執(zhí)行器中執(zhí)行

2. Promise.prototype.then 方法

格式:(onResolved, onRejected) => {}
(1)onResolved 函數(shù): 成功 的回調(diào)函數(shù) (value) => {}
(2)onRejected 函數(shù): 失敗 的回調(diào)函數(shù) (reason) => {}
說明:
指定 用于得到成功 value 的成功回調(diào)函數(shù),和用于得到失敗 reason 的失敗回調(diào)函數(shù)
② then()方法會返回一個新的 promise 對象

3. Promise.prototype.catch 方法

格式:(onRejected) => {}
(1)onRejected 函數(shù): 失敗 的回調(diào)函數(shù) (reason) => {}
說明: then()的語法糖, 相當于 then(null, onRejected)

new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('成功的數(shù)據(jù)');
        // reject('失敗的數(shù)據(jù)'); //只會執(zhí)行其中一個,因為promise的狀態(tài)只能改變一次
    }, 1000);
})
.then((value) => {
    console.log('操作成功,接收的數(shù)據(jù)為:' + value);
})
.catch((reason) => {
    console.log('操作失敗,接收的數(shù)據(jù)為:' + reason);
});
4. Promise.resolve 方法

格式: (value) => {}
(1)參數(shù)value: 成功的數(shù)據(jù)promise 對象。
說明: 返回一個 成功或失敗promise 對象

5. Promise.reject 方法

格式:(reason) => {}
(1)參數(shù)reason: 失敗的原因。
說明: 返回一個 失敗的 promise 對象。

// 生成一個成功數(shù)據(jù)為1的Promise對象:兩種方式對比
const p1 = new Promise((resolve, reject) => {
    resolve(1);
});
const p2 = Promise.resolve(2);
const p3 = Promise.reject(3);
6. Promise.all 方法

格式:([promise1,promise2]) => {}
(1)參數(shù): 包含 n 個 promise 的 數(shù)組
(2)返回一個 新的 promise, 只有所有的 promise 都成功才成功, 只要有一個失敗了就直接失敗。
(3)返回的數(shù)組中的結(jié)果順序和 傳入的promise順序 一致,與執(zhí)行完成的先后順序無關(guān)。

// 接上面代碼
const pAll = Promise.all([p1, p2]);
pAll.then(
    (values) => {
        console.log('所有promise都成功了,結(jié)果為:', values); // 執(zhí)行成功的回調(diào)函數(shù),因為p1,p2都是成功的Promise
    },
    (reasons) => {
        console.log('至少一個promise失敗了,結(jié)構(gòu)為:', reasons);
    }
);
7.Promise.race 方法

格式:([promise1,promise2]) => {}
(1) 參數(shù): 包含 n 個 promise 的數(shù)組
(2) 返回一個 新的 promise, 第一個完成的 promise 的結(jié)果狀態(tài)就是最終的結(jié)果狀態(tài)
(3)最終結(jié)果只和 實際執(zhí)行順序有關(guān),與傳入的promise順序無關(guān)

// 接上面代碼
const pRace = Promise.race([p3, p2, p1]);
pRace.then(
    (value) => {
        console.log('race結(jié)果是成功的:', value); 
    },
    (reason) => {
        console.log('race結(jié)果是失敗的:', reason); //執(zhí)行失敗的回調(diào)函數(shù),因為三個promise都沒有異步操作,p3首先執(zhí)行完成
    }
);

四、Promise的幾個關(guān)鍵問題

1.如何改變 promise 的狀態(tài)

(1) 調(diào)用回調(diào)函數(shù)resolve(value):如果當前是 pending 就會變?yōu)?resolved
(2) 調(diào)用回調(diào)函數(shù)reject(reason):如果當前是 pending 就會變?yōu)?rejected
(3) 拋出異常:如果當前是 pending 就會變?yōu)?rejected

const p = new Promise((resolve, reject) => {
    // resolve(1); // promise變?yōu)閞esolved成功狀態(tài)
    // reject(2); // promise變?yōu)閞ejected失敗狀態(tài)
    // throw new Error(3); // promise變?yōu)閞ejected失敗狀態(tài),reason為拋出的內(nèi)容
    throw 4;
});
2.一個 promise 指定多個成功或失敗回調(diào)函數(shù), 都會被調(diào)用

(1)當 promise 改變狀態(tài)時 會調(diào)用 所有 對應(yīng)的回調(diào)函數(shù)

const p = new Promise((resolve, reject) => {
    resolve(1); 
})
p.then(
    (value) => {
        console.log('成功:', value);
    },
);
// 重新指定回調(diào)函數(shù)
p.then(
    (value) => {
        console.log('重新指定成功的回調(diào)函數(shù):', value);
    },
);
3.改變 promise 狀態(tài)和指定回調(diào)函數(shù)誰先誰后

(1) 都有可能, 正常情況下是 先指定回調(diào)再改變狀態(tài), 但也可以先改狀態(tài)再指定回調(diào)。
(2) 如何先改狀態(tài)再指定回調(diào)?
① 在執(zhí)行器中直接調(diào)用 resolve()/reject()
② 延遲更長時間才調(diào)用 then()
(3) 什么時候才能得到數(shù)據(jù)?
① 如果先指定的回調(diào),先將回調(diào)函數(shù)保存; 當狀態(tài)發(fā)生改變時, 回調(diào)函數(shù)就會調(diào)用, 得到數(shù)據(jù)。
② 如果先改變的狀態(tài), 那當指定回調(diào)時, 回調(diào)函數(shù)就會調(diào)用, 得到數(shù)據(jù)。

const p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(1); // 后改變狀態(tài)(同時指定成功的數(shù)據(jù)),異步執(zhí)行回調(diào)函數(shù)
    }, 1000);
});
//先指定回調(diào)函數(shù),保存當前指定的回調(diào)函數(shù)
p1.then((value) => {
    console.log('成功:', value);
});

const p2 = new Promise((resolve, reject) => {
    resolve(2); //先改變狀態(tài)(同時指定成功的數(shù)據(jù))
}).then((value) => {
    // 后指定回調(diào)函數(shù),異步執(zhí)行回調(diào)函數(shù)
    console.log('成功:', value);
});
4.promise.then()返回的新 promise 的結(jié)果狀態(tài)由什么決定

(1) 簡單表達: 由 then()指定的回調(diào)函數(shù) 【執(zhí)行的結(jié)果】決定,即then()返回的 promise 的結(jié)果決定。
(2) 詳細表達:
① 如果返回的是 非 promise 的任意值, 新 promise 變?yōu)?resolved成功狀態(tài), value 為返回的值。
② 如果返回的是另一個 新 promise, 此 promise 的結(jié)果就會成為新 promise 的結(jié)果。
③ 如果 拋出異常, 新 promise 變?yōu)?rejected失敗狀態(tài), reason 為拋出的異常。

            new Promise((resolve, reject) => {
                resolve(1);
            })
             .then(
                (value) => {
                    console.log('onResolved()1:', value);
                    return 2;                      // 返回非promise,相當于返回一個成功的promise
                    // return Promise.resolve(3);  //返回成功的promise
                    // return Promise.reject(4);   // 返回失敗的promise
                    // throw 5;                    // 拋出異常,相當于返回一個失敗的promise
                  },
                  (reason) => {
                      console.log('onRejected()1:', reason);
                  })
                .then(
                    (value) => {
                        console.log('onResolved()2:', value);  // 前面then()方法最終返回的是一個成功的promise,成功結(jié)果為 2
                    },
                    (reason) => {
                        console.log('onRejected()2:', reason);
                    }
                );
5.promise 串連多個操作任務(wù)

(1) promise 的 then()返回一個新的 promise, 可以看成 then()的鏈式調(diào)用。
(2) 通過 then 的鏈式調(diào)用串連多個同步 或 異步任務(wù)。

            new Promise((resolve, reject) => {
                //異步任務(wù)1
                setTimeout(() => {
                    console.log('執(zhí)行任務(wù)1(異步)');
                    resolve(1);
                }, 1000);
            })
             .then((value) => {
                console.log('任務(wù)1的結(jié)果:', value);
                console.log('執(zhí)行任務(wù)2(同步)'); //同步任務(wù)2
                return 2;
              })
              .then((value) => {
                  console.log('任務(wù)2的結(jié)果:', value);
                  // 異步任務(wù)3,返回一個新的promise對象
                  return new Promise((resolve, reject) => {
                      setTimeout(() => {
                          console.log('執(zhí)行任務(wù)3(異步)');
                          resolve(3);
                      }, 1000);
                  });
                })
                .then((value) => {
                    console.log('任務(wù)3的結(jié)果:', value);
                });
6.promise 異常穿透

(1) 當使用 promise 的 then 鏈式調(diào)用時, 可以只在 最后 指定一個失敗的回調(diào)。
(2) 前面任何操作出了異常, 都能夠傳到最后失敗的回調(diào)中進行處理。

new Promise((resolve, reject) => {
  reject(1);
})
  .then(
    (value) => {}
        // then鏈式調(diào)用時不對失敗進行處理,相當于執(zhí)行了下面代碼
        // (reason) => {
        //  throw reason;
        //  return Promise.reject(reason);
        // }
    )
    .then((value) => {})
    .then((value) => {})
    .catch((reason) => {
            console.log('捕捉到異常:', reason);
    });
7.如何中斷 promise 鏈式調(diào)用

(1) 當使用 promise 的 then 鏈式調(diào)用時, 在中間中斷, 不再調(diào)用后面的回調(diào)函數(shù)。
(2) 在回調(diào)函數(shù)中返回一個 pendding 狀態(tài)的 promise 對象。

new Promise((resolve, reject) => {
   resolve(1);
})
  .then((value) => {
        console.log('onResolved1():', value);
        return new Promise(() => {}); // 返回一個pending狀態(tài)的promise,后面的回調(diào)函數(shù)就不會被調(diào)用
   })
   .then((value) => {
         console.log('onResolved2():', value);
   });
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • 1. 實例對象與函數(shù)對象的區(qū)別 函數(shù)對象:將函數(shù)作為對象使用時,簡稱為函數(shù)對象 實例對象:new 函數(shù)產(chǎn)生的對象,...
    雨溪灘閱讀 319評論 0 0
  • 1,什么是promise? 1,抽象表達:promise是js中進行一步編程的新的解決方案(舊的是—純回調(diào)函數(shù))2...
    jasmine_6aa1閱讀 318評論 0 0
  • 異步 不連續(xù)的執(zhí)行,就叫做異步。相應(yīng)地,連續(xù)的執(zhí)行就叫做同步。 通常異步是處理一些耗時的操作。 回想在ES6沒出現(xiàn)...
    哎嘿沁閱讀 881評論 0 0
  • Promise深入 + 自定義Promise 1. 準備 1.1. 函數(shù)對象與實例對象 函數(shù)對象: 將函數(shù)作為對象...
    文弱書生Mr齊閱讀 388評論 0 2
  • 1、準備知識 1、回調(diào)函數(shù): 理解:一個函數(shù),自己定義的,自己沒有調(diào)用,但是函數(shù)執(zhí)行了。 同步回調(diào):立即執(zhí)行,完全...
    Shy啊閱讀 1,297評論 0 1

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