日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

promise then err_Promise 原理解析与实现(遵循Promise/A+规范)

發布時間:2025/3/15 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 promise then err_Promise 原理解析与实现(遵循Promise/A+规范) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1什么是Promise?

Promise是JS異步編程中的重要概念,異步抽象處理對象,是目前比較流行Javascript異步編程解決方案之一

2對于幾種常見異步編程方案
  • 回調函數

  • 事件監聽

  • 發布/訂閱

  • Promise對象

這里就拿回調函數說說

1.對于回調函數 我們用Jquery的ajax獲取數據時 都是以回調函數方式獲取的數據

$.get(url,?(data)?=>?{
????console.log(data)
)

2.如果說 當我們需要發送多個異步請求 并且每個請求之間需要相互依賴 那這時 我們只能 以嵌套方式來解決 形成 “回調地獄”

$.get(url,?data1?=>?{
????console.log(data1)
????$.get(data1.url,?data2?=>?{
????????console.log(data1)
????})
})

這樣一來,在處理越多的異步邏輯時,就需要越深的回調嵌套,這種編碼模式的問題主要有以下幾個:

  • 代碼邏輯書寫順序與執行順序不一致,不利于閱讀與維護。

  • 異步操作的順序變更時,需要大規模的代碼重構。

  • 回調函數基本都是匿名函數,bug 追蹤困難。

  • 回調函數是被第三方庫代碼(如上例中的 ajax )而非自己的業務代碼所調用的,造成了 IoC 控制反轉。

Promise 處理多個相互關聯的異步請求

1.而我們Promise 可以更直觀的方式 來解決 “回調地獄”

const?request?=?url?=>?{?
????return?new?Promise((resolve,?reject)?=>?{
????????$.get(url,?data?=>?{
????????????resolve(data)
????????});
????})
};

//?請求data1
request(url).then(data1?=>?{
????return?request(data1.url);???
}).then(data2?=>?{
????return?request(data2.url);
}).then(data3?=>?{
????console.log(data3);
}).catch(err?=>?throw?new?Error(err));

2.相信大家在 vue/react 都是用axios fetch 請求數據 也都支持 Promise API

import?axios?from?'axios';
axios.get(url).then(data?=>?{
???console.log(data)
})

Axios 是一個基于 promise 的 HTTP 庫,可以用在瀏覽器和 node.js 中。

3Promise使用

1.Promise 是一個構造函數, new Promise 返回一個 promise對象 接收一個excutor執行函數作為參數, excutor有兩個函數類型形參resolve reject

const?promise?=?new?Promise((resolve,?reject)?=>?{
???????//?異步處理
???????//?處理結束后、調用resolve?或?reject
});

2.promise相當于一個狀態機

promise的三種狀態

  • pending

  • fulfilled

  • rejected

1.promise 對象初始化狀態為 pending?

2.當調用resolve(成功),會由pending => fulfilled?

3.當調用reject(失敗),會由pending => rejected

注意promsie狀態 只能由 pending => fulfilled/rejected, 一旦修改就不能再變

3.promise對象方法

1.then方法注冊 當resolve(成功)/reject(失敗)的回調函數

//?onFulfilled?是用來接收promise成功的值
//?onRejected?是用來接收promise失敗的原因
promise.then(onFulfilled,?onRejected);

then方法是異步執行的

2.resolve(成功) onFulfilled會被調用

const?promise?=?new?Promise((resolve,?reject)?=>?{
???resolve('fulfilled');?//?狀態由?pending?=>?fulfilled
});
promise.then(result?=>?{?//?onFulfilled
????console.log(result);?//?'fulfilled'?
},?reason?=>?{?//?onRejected?不會被調用

})

3.reject(失敗) onRejected會被調用

const?promise?=?new?Promise((resolve,?reject)?=>?{
???reject('rejected');?//?狀態由?pending?=>?rejected
});
promise.then(result?=>?{?//?onFulfilled?不會被調用

},?reason?=>?{?//?onRejected?
????console.log(reason);?//?'rejected'
})

4.promise.catch

在鏈式寫法中可以捕獲前面then中發送的異常

promise.catch(onRejected)
相當于
promise.then(null,?onRrejected);

//?注意
//?onRejected?不能捕獲當前onFulfilled中的異常
promise.then(onFulfilled,?onRrejected);?

//?可以寫成:
promise.then(onFulfilled)
???????.catch(onRrejected);???
4.Promise chain

promise.then方法每次調用 都返回一個新的promise對象 所以可以鏈式寫法

function?taskA()?{
????console.log("Task?A");
}
function?taskB()?{
????console.log("Task?B");
}
function?onRejected(error)?{
????console.log("Catch?Error:?A?or?B",?error);
}

var?promise?=?Promise.resolve();
promise
????.then(taskA)
????.then(taskB)
????.catch(onRejected)?//?捕獲前面then方法中的異常?
5.Promise的靜態方法
  • Promise.resolve 返回一個fulfilled狀態的promise對象

  • Promise.resolve('hello').then(function(value){
    ????console.log(value);
    });

    Promise.resolve('hello');
    //?相當于
    const?promise?=?new?Promise(resolve?=>?{
    ???resolve('hello');
    });

    2.Promise.reject 返回一個rejected狀態的promise對象

    Promise.reject(24);
    new?Promise((resolve,?reject)?=>?{
    ???reject(24);
    });

    3.Promise.all 接收一個promise對象數組為參數

    只有全部為resolve才會調用 通常會用來處理 多個并行異步操作

    const?p1?=?new?Promise((resolve,?reject)?=>?{
    ????resolve(1);
    });

    const?p2?=?new?Promise((resolve,?reject)?=>?{
    ????resolve(2);
    });

    const?p3?=?new?Promise((resolve,?reject)?=>?{
    ????reject(3);
    });

    Promise.all([p1,?p2,?p3]).then(data?=>?{?
    ????console.log(data);?//?[1,?2,?3]?結果順序和promise實例數組順序是一致的
    },?err?=>?{
    ????console.log(err);
    });

    4.Promise.race 接收一個promise對象數組為參數

    Promise.race 只要有一個promise對象進入 FulFilled 或者 Rejected 狀態的話,就會繼續進行后面的處理。

    function?timerPromisefy(delay)?{
    ????return?new?Promise(function?(resolve,?reject)?{
    ????????setTimeout(function?()?{
    ????????????resolve(delay);
    ????????},?delay);
    ????});
    }
    var?startDate?=?Date.now();

    Promise.race([
    ????timerPromisefy(10),
    ????timerPromisefy(20),
    ????timerPromisefy(30)
    ]).then(function?(values)?{
    ????console.log(values);?//?10
    });

    5.Promise的finally

    Promise.prototype.finally?=?function?(callback)?{
    ??let?P?=?this.constructor;
    ??return?this.then(
    ????value??=>?P.resolve(callback()).then(()?=>?value),
    ????reason?=>?P.resolve(callback()).then(()?=>?{?throw?reason?})
    ??);
    };
    4Promise代碼實現/**
    ?*?Promise?實現?遵循promise/A+規范
    ?*?Promise/A+規范譯文:
    ?*?https://malcolmyu.github.io/2015/06/12/Promises-A-Plus/#note-4
    ?*/

    //?promise?三個狀態
    const?PENDING?=?"pending";
    const?FULFILLED?=?"fulfilled";
    const?REJECTED?=?"rejected";

    function?Promise(excutor)?{
    ????let?that?=?this;?//?緩存當前promise實例對象
    ????that.status?=?PENDING;?//?初始狀態
    ????that.value?=?undefined;?//?fulfilled狀態時?返回的信息
    ????that.reason?=?undefined;?//?rejected狀態時?拒絕的原因
    ????that.onFulfilledCallbacks?=?[];?//?存儲fulfilled狀態對應的onFulfilled函數
    ????that.onRejectedCallbacks?=?[];?//?存儲rejected狀態對應的onRejected函數

    ????function?resolve(value)?{?//?value成功態時接收的終值
    ????????if(value?instanceof?Promise)?{
    ????????????return?value.then(resolve,?reject);
    ????????}

    ????????//?為什么resolve?加setTimeout?
    ????????//?2.2.4規范?onFulfilled?和?onRejected?只允許在?execution?context?棧僅包含平臺代碼時運行.
    ????????//?注1?這里的平臺代碼指的是引擎、環境以及?promise?的實施代碼。實踐中要確保?onFulfilled?和?onRejected?方法異步執行,且應該在?then?方法被調用的那一輪事件循環之后的新執行棧中執行。

    ????????setTimeout(()?=>?{
    ????????????//?調用resolve?回調對應onFulfilled函數
    ????????????if?(that.status?===?PENDING)?{
    ????????????????//?只能由pending狀態?=>?fulfilled狀態?(避免調用多次resolve?reject)
    ????????????????that.status?=?FULFILLED;
    ????????????????that.value?=?value;
    ????????????????that.onFulfilledCallbacks.forEach(cb?=>?cb(that.value));
    ????????????}
    ????????});
    ????}

    ????function?reject(reason)?{?//?reason失敗態時接收的拒因
    ????????setTimeout(()?=>?{
    ????????????//?調用reject?回調對應onRejected函數
    ????????????if?(that.status?===?PENDING)?{
    ????????????????//?只能由pending狀態?=>?rejected狀態?(避免調用多次resolve?reject)
    ????????????????that.status?=?REJECTED;
    ????????????????that.reason?=?reason;
    ????????????????that.onRejectedCallbacks.forEach(cb?=>?cb(that.reason));
    ????????????}
    ????????});
    ????}

    ????//?捕獲在excutor執行器中拋出的異常
    ????//?new?Promise((resolve,?reject)?=>?{
    ????//?????throw?new?Error('error?in?excutor')
    ????//?})
    ????try?{
    ????????excutor(resolve,?reject);
    ????}?catch?(e)?{
    ????????reject(e);
    ????}
    }

    /**
    ?*?resolve中的值幾種情況:
    ?*?1.普通值
    ?*?2.promise對象
    ?*?3.thenable對象/函數
    ?*/

    /**
    ?*?對resolve?進行改造增強?針對resolve中不同值情況?進行處理
    ?*?@param??{promise}?promise2?promise1.then方法返回的新的promise對象
    ?*?@param??{[type]}?x?????????promise1中onFulfilled的返回值
    ?*?@param??{[type]}?resolve???promise2的resolve方法
    ?*?@param??{[type]}?reject????promise2的reject方法
    ?*/
    function?resolvePromise(promise2,?x,?resolve,?reject)?{
    ????if?(promise2?===?x)?{??//?如果從onFulfilled中返回的x?就是promise2?就會導致循環引用報錯
    ????????return?reject(new?TypeError('循環引用'));
    ????}

    ????let?called?=?false;?//?避免多次調用
    ????//?如果x是一個promise對象?(該判斷和下面?判斷是不是thenable對象重復?所以可有可無)
    ????if?(x?instanceof?Promise)?{?//?獲得它的終值?繼續resolve
    ????????if?(x.status?===?PENDING)?{?//?如果為等待態需等待直至?x?被執行或拒絕?并解析y值
    ????????????x.then(y?=>?{
    ????????????????resolvePromise(promise2,?y,?resolve,?reject);
    ????????????},?reason?=>?{
    ????????????????reject(reason);
    ????????????});
    ????????}?else?{?//?如果?x?已經處于執行態/拒絕態(值已經被解析為普通值),用相同的值執行傳遞下去?promise
    ????????????x.then(resolve,?reject);
    ????????}
    ????????//?如果?x?為對象或者函數
    ????}?else?if?(x?!=?null?&&?((typeof?x?===?'object')?||?(typeof?x?===?'function')))?{
    ????????try?{?//?是否是thenable對象(具有then方法的對象/函數)
    ????????????let?then?=?x.then;
    ????????????if?(typeof?then?===?'function')?{
    ????????????????then.call(x,?y?=>?{
    ????????????????????if(called)?return;
    ????????????????????called?=?true;
    ????????????????????resolvePromise(promise2,?y,?resolve,?reject);
    ????????????????},?reason?=>?{
    ????????????????????if(called)?return;
    ????????????????????called?=?true;
    ????????????????????reject(reason);
    ????????????????})
    ????????????}?else?{?//?說明是一個普通對象/函數
    ????????????????resolve(x);
    ????????????}
    ????????}?catch(e)?{
    ????????????if(called)?return;
    ????????????called?=?true;
    ????????????reject(e);
    ????????}
    ????}?else?{
    ????????resolve(x);
    ????}
    }

    /**
    ?*?[注冊fulfilled狀態/rejected狀態對應的回調函數]
    ?*?@param??{function}?onFulfilled?fulfilled狀態時?執行的函數
    ?*?@param??{function}?onRejected??rejected狀態時?執行的函數
    ?*?@return?{function}?newPromsie??返回一個新的promise對象
    ?*/
    Promise.prototype.then?=?function(onFulfilled,?onRejected)?{
    ????const?that?=?this;
    ????let?newPromise;
    ????//?處理參數默認值?保證參數后續能夠繼續執行
    ????onFulfilled?=
    ????????typeof?onFulfilled?===?"function"???onFulfilled?:?value?=>?value;
    ????onRejected?=
    ????????typeof?onRejected?===?"function"???onRejected?:?reason?=>?{
    ????????????throw?reason;
    ????????};

    ????//?then里面的FULFILLED/REJECTED狀態時?為什么要加setTimeout??
    ????//?原因:
    ????//?其一?2.2.4規范?要確保?onFulfilled?和?onRejected?方法異步執行(且應該在?then?方法被調用的那一輪事件循環之后的新執行棧中執行)?所以要在resolve里加上setTimeout
    ????//?其二?2.2.6規范?對于一個promise,它的then方法可以調用多次.(當在其他程序中多次調用同一個promise的then時?由于之前狀態已經為FULFILLED/REJECTED狀態,則會走的下面邏輯),所以要確保為FULFILLED/REJECTED狀態后?也要異步執行onFulfilled/onRejected

    ????//?其二?2.2.6規范?也是resolve函數里加setTimeout的原因
    ????//?總之都是?讓then方法異步執行?也就是確保onFulfilled/onRejected異步執行

    ????//?如下面這種情景?多次調用p1.then
    ????//?p1.then((value)?=>?{?//?此時p1.status?由pedding狀態?=>?fulfilled狀態
    ????//?????console.log(value);?//?resolve
    ????//?????//?console.log(p1.status);?//?fulfilled
    ????//?????p1.then(value?=>?{?//?再次p1.then?這時已經為fulfilled狀態?走的是fulfilled狀態判斷里的邏輯?所以我們也要確保判斷里面onFuilled異步執行
    ????//?????????console.log(value);?//?'resolve'
    ????//?????});
    ????//?????console.log('當前執行棧中同步代碼');
    ????//?})
    ????//?console.log('全局執行棧中同步代碼');
    ????//

    ????if?(that.status?===?FULFILLED)?{?//?成功態
    ????????return?newPromise?=?new?Promise((resolve,?reject)?=>?{
    ????????????setTimeout(()?=>?{
    ????????????????try{
    ????????????????????let?x?=?onFulfilled(that.value);
    ????????????????????resolvePromise(newPromise,?x,?resolve,?reject);?//?新的promise?resolve?上一個onFulfilled的返回值
    ????????????????}?catch(e)?{
    ????????????????????reject(e);?//?捕獲前面onFulfilled中拋出的異常?then(onFulfilled,?onRejected);
    ????????????????}
    ????????????});
    ????????})
    ????}

    ????if?(that.status?===?REJECTED)?{?//?失敗態
    ????????return?newPromise?=?new?Promise((resolve,?reject)?=>?{
    ????????????setTimeout(()?=>?{
    ????????????????try?{
    ????????????????????let?x?=?onRejected(that.reason);
    ????????????????????resolvePromise(newPromise,?x,?resolve,?reject);
    ????????????????}?catch(e)?{
    ????????????????????reject(e);
    ????????????????}
    ????????????});
    ????????});
    ????}

    ????if?(that.status?===?PENDING)?{?//?等待態
    ????????//?當異步調用resolve/rejected時?將onFulfilled/onRejected收集暫存到集合中
    ????????return?newPromise?=?new?Promise((resolve,?reject)?=>?{
    ????????????that.onFulfilledCallbacks.push((value)?=>?{
    ????????????????try?{
    ????????????????????let?x?=?onFulfilled(value);
    ????????????????????resolvePromise(newPromise,?x,?resolve,?reject);
    ????????????????}?catch(e)?{
    ????????????????????reject(e);
    ????????????????}
    ????????????});
    ????????????that.onRejectedCallbacks.push((reason)?=>?{
    ????????????????try?{
    ????????????????????let?x?=?onRejected(reason);
    ????????????????????resolvePromise(newPromise,?x,?resolve,?reject);
    ????????????????}?catch(e)?{
    ????????????????????reject(e);
    ????????????????}
    ????????????});
    ????????});
    ????}
    };

    /**
    ?*?Promise.all?Promise進行并行處理
    ?*?參數:?promise對象組成的數組作為參數
    ?*?返回值:?返回一個Promise實例
    ?*?當這個數組里的所有promise對象全部變為resolve狀態的時候,才會resolve。
    ?*/
    Promise.all?=?function(promises)?{
    ????return?new?Promise((resolve,?reject)?=>?{
    ????????let?done?=?gen(promises.length,?resolve);
    ????????promises.forEach((promise,?index)?=>?{
    ????????????promise.then((value)?=>?{
    ????????????????done(index,?value)
    ????????????},?reject)
    ????????})
    ????})
    }

    function?gen(length,?resolve)?{
    ????let?count?=?0;
    ????let?values?=?[];
    ????return?function(i,?value)?{
    ????????values[i]?=?value;
    ????????if?(++count?===?length)?{
    ????????????console.log(values);
    ????????????resolve(values);
    ????????}
    ????}
    }

    /**
    ?*?Promise.race
    ?*?參數:?接收?promise對象組成的數組作為參數
    ?*?返回值:?返回一個Promise實例
    ?*?只要有一個promise對象進入?FulFilled?或者?Rejected?狀態的話,就會繼續進行后面的處理(取決于哪一個更快)
    ?*/
    Promise.race?=?function(promises)?{
    ????return?new?Promise((resolve,?reject)?=>?{
    ????????promises.forEach((promise,?index)?=>?{
    ???????????promise.then(resolve,?reject);
    ????????});
    ????});
    }

    //?用于promise方法鏈時?捕獲前面onFulfilled/onRejected拋出的異常
    Promise.prototype.catch?=?function(onRejected)?{
    ????return?this.then(null,?onRejected);
    }

    Promise.resolve?=?function?(value)?{
    ????return?new?Promise(resolve?=>?{
    ????????resolve(value);
    ????});
    }

    Promise.reject?=?function?(reason)?{
    ????return?new?Promise((resolve,?reject)?=>?{
    ????????reject(reason);
    ????});
    }

    /**
    ?*?基于Promise實現Deferred的
    ?*?Deferred和Promise的關系
    ?*?-?Deferred?擁有?Promise
    ?*?-?Deferred?具備對?Promise的狀態進行操作的特權方法(resolve?reject)
    ?*
    ?*參考jQuery.Deferred
    ?*url:?http://api.jquery.com/category/deferred-object/
    ?*/
    Promise.deferred?=?function()?{?//?延遲對象
    ????let?defer?=?{};
    ????defer.promise?=?new?Promise((resolve,?reject)?=>?{
    ????????defer.resolve?=?resolve;
    ????????defer.reject?=?reject;
    ????});
    ????return?defer;
    }

    /**
    ?*?Promise/A+規范測試
    ?*?npm?i?-g?promises-aplus-tests
    ?*?promises-aplus-tests?Promise.js
    ?*/

    try?{
    ??module.exports?=?Promise
    }?catch?(e)?{
    }

    Promise測試

    npm?i?-g?promises-aplus-tests
    promises-aplus-tests?Promise.js

    如何主動終止Promise調用鏈

    const?p1?=?new?Promise((resolve,?reject)?=>?{
    ??setTimeout(()?=>?{?//?異步操作
    ??????resolve('start')
    ??},?1000);
    });

    p1.then((result)?=>?{
    ???console.log('a',?result);?
    ???return?Promise.reject('中斷后續調用');?//?此時rejected的狀態將直接跳到catch里,剩下的調用不會再繼續
    }).then(result?=>?{
    ???console.log('b',?result);
    }).then(result?=>?{
    ???console.log('c',?result);
    }).catch(err?=>?{
    ???console.log(err);
    });

    //?a?start
    //?中斷后續調用

    珠峰前端課程開課時間

    2019年3月11日?《零基礎入門課程》?2019年3月4日? ?《全日制框架課程》

    2019年3月4日???《周末班框架課程》?

    2019年3月11日?《前端就業課程》

    與50位技術專家面對面20年技術見證,附贈技術全景圖

    總結

    以上是生活随笔為你收集整理的promise then err_Promise 原理解析与实现(遵循Promise/A+规范)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。