摘要:被觀察者管理內部和的狀態(tài)轉變,同時通過構造函數(shù)中傳遞的和方法以主動觸發(fā)狀態(tài)轉變和通知觀察者。第一個回調函數(shù)是對象的狀態(tài)變?yōu)闀r調用,第二個回調函數(shù)是對象的狀態(tài)變?yōu)闀r調用可選實現(xiàn)主要實現(xiàn)第一步,初步構建。
Promise 含義
Promise是異步編程的一種解決方案,比傳統(tǒng)的解決方案(回調函數(shù)和事件)更合合理、強大。所謂Promise,簡單來說就是一個容器,里面保存著某個未來才會結束的事件(通常是一個異步操作)的結果。從語法上說,Promies是一個對象,從它可以獲取異步操作的消息。Promise提供統(tǒng)一的API,各種異步操作都可以用同樣的方法進行處理
Promise對象有以下兩個特點對象的狀態(tài)不受外界影響。
一旦狀態(tài)改變,就不會再變,任何時候都可以得到這個結果
promise有三種狀態(tài),pending(進行中)、fulfilled/resolved(已成功)和rejected(已失敗)
Promise優(yōu)點將異步操作以同步操作的流程表達出來,避免了回調地獄
Promise對象提供統(tǒng)一的接口,更加容易控制異步操作
Promise缺點無法中途終止,一旦新建立即執(zhí)行
如果不設置回調函數(shù),Promise內部拋出的錯誤,不會反應到外部
當處于pending狀態(tài)時,無法得知目前進展到哪一個階段
Promise設計原理Promise的實現(xiàn)過程,其主要使用了設計模式中的觀察者模式:
通過Promise.prototype.then和Promise.prototype.catch方法將觀察者方法注冊到被觀察者Promise對象中,同時返回一個新的Promise對象,以便可以鏈式調用。
被觀察者管理內部pending、fulfilled和rejected的狀態(tài)轉變,同時通過構造函數(shù)中傳遞的resolve和reject方法以主動觸發(fā)狀態(tài)轉變和通知觀察者。
Promise 是通過.then方法來實現(xiàn)多個異步操作的順序執(zhí)行
Promise的內部也有一個 defers 隊列存放事件,而 .then 方法的作用和發(fā)布訂閱模式的on方法一樣是用來訂閱事件的,每次調用 .then 方法就會往defers隊列中放入一個事件,當異步操作完成時, resolve方法標示前一個異步過程完成并從defers隊列中取出第一個事件執(zhí)行并返回當前對象保證鏈式調用,以此類推,就完成了所有異步過程的隊列執(zhí)行
實例化Promise,返回Promise對象 const promise = new Promise(function(resolve, reject) { // ... some code if (/* 異步操作成功 */){ resolve(value); } else { reject(error); } }); promise.then(function(value){ // success }, function(err){ // failure })
Promise對象是一個構造函數(shù),用來生成Promise實例。通過new返回一個Promise實例
Promise構造函數(shù)接受一個函數(shù)作為參數(shù),該函數(shù)接受resolve和reject兩個回調函數(shù)作為參數(shù),它們由 JavaScript 引擎提供,不用自己部署,用來改變Promise的狀態(tài)
resolve函數(shù),將Promise對象的狀態(tài)從 pending => resolved,在異步操作成功時調用,并將異步操作的結果,作為參數(shù)傳遞出去;
reject函數(shù),將Promise對象的狀態(tài)從 pending => rejected,在異步操作失敗時調用,并將異步操作報出的錯誤,作為參數(shù)傳遞出去
Promise.prototype.thenthen是Promise構造函數(shù)原型鏈上的方法,Promise.prototype.then,then方法分別指定resolved狀態(tài)和rejected狀態(tài)的回調函數(shù)
then方法可以接受兩個回調函數(shù)作為參數(shù)。第一個回調函數(shù)是Promise對象的狀態(tài)變?yōu)閞esolved時調用,第二個回調函數(shù)是Promise對象的狀態(tài)變?yōu)閞ejected時調用【可選】
Promise 實現(xiàn) 主要實現(xiàn)第一步,初步構建。Promise 的參數(shù)是函數(shù) executor,把內部定義 resolve 方法作為參數(shù)傳到 executor 中,調用 executor。當異步操作成功后會調用 resolve 方法,然后就會執(zhí)行 then 中注冊的回調函數(shù);并通過then中的return this實現(xiàn)鏈式調用
function MyPromise(executor) { var value = null, callbacks = []; //callbacks為數(shù)組,因為可能同時有很多個回調 this.then = function (onFulfilled) { callbacks.push(onFulfilled); return this // 返回Promise對象,實現(xiàn)鏈式調用 }; // 成功回調 function resolve(value) { setTimeout(function() { // Promises/A+規(guī)范明確要求回調需要通過異步方式執(zhí)行,用以保證一致可靠的執(zhí)行順序;通過setTimeout機制,將resolve中執(zhí)行回調的邏輯放置到JS任務隊列末尾,以保證在resolve執(zhí)行時,then方法的回調函數(shù)已經(jīng)注冊完成 callbacks.forEach(function (callback) { callback(value); }); }, 0) } executor(resolve); }
第二步,添加狀態(tài)state
function MyPromise(executor) { var state = "pending", value = null, callbacks = []; this.then = function (onFulfilled) { if (state === "pending") { callbacks.push(onFulfilled); return this; } onFulfilled(value); return this; }; function resolve(newValue) { value = newValue; state = "fulfilled"; setTimeout(function () { callbacks.forEach(function (callback) { callback(value); }); }, 0); } executor(resolve); }
完整實現(xiàn)代碼
function MyPromise(executor) { this._status = "PENDING" this._value = null this._reason = null this._resolveFns = [] this._rejectFns = [] var handler = function(state, value) { if (this.state !== "PENDING") return let promise = this let fns = [] setTimeout(function() { promise.state = state let st = state === "FULFILLED" fns = st ? promise["_resolveFns"] : promise["_resolveFns"] fns.forEach(fn => { value = fn.call(promise, value) || value }) promise[st ? "_value" : "_reason"] = value; promise["_resolveFns"] = promise["_resolveFns"] = undefined; }, 0) } var resolve = function(value) { handler.call(this, "FULFILLED", value); } var reject = function(reason){ handler.call(this, "REJECTED", reason); } executor(resolve,reject) } MyPromise.prototype.then = function(resolveFn, rejectFn) { var promise = this //串行 return new Promise(function(resolveNext, rejectNext) { // 在 then 方法,對then方法的回調函數(shù)返回結果 ret 進行判斷,如果是一個 promise 對象,就會調用其 then 方法,形成一個嵌套,直到其不是promise對象為止 function resolveHandler(value) { var result = typeof resolveFn === "function" && resolveFn(value) || value if (result && typeof result.then === "function") { result.then(function(value) { resolveNext(value) }, function(reason) { rejectNext(reason) }) } else { resolveNext(result) } } function rejectHandler(reason) { var reason = typeof rejectFn === "function" && rejectFn(reason) || reason rejectNext(reason) } if(promise._status === "PENDING"){ promise._resolveFns.push(resolveHandler); promise._rejectFns.push(rejectHandler); }else if(promise._status === "FULFILLED"){ // 狀態(tài)改變后的then操作,立刻執(zhí)行 resolveHandler(promise._value); }else if(promise._status === "REJECTED"){ rejectHandler(promise._reason); } }) }
測試
// 實際上,fn中的resolve、reject函數(shù)分別是then方法中對應的函數(shù)參數(shù) var fn5 = function(resolve, reject){ console.log("oooo1") resolve("5"); console.log("ssss1") } var fn6 = function(resolve, reject){ resolve("6"); } new MyPromise(fn5).then(function(data){ console.log(data); return new MyPromise(fn6); }).then(function(data){ console.log(data); });其他常用 Promise API 實現(xiàn)
MyPromise.prototype.catch = function(reject) { return this.then(undefined, reject) } MyPromise.prototype.delay = function(time) { return this.then(function(ori){ return Promise.delay(ms, value || ori); }) } MyPromise.delay = function(ms, value) { return new MyPromise(function(resolve, reject){ setTimeout(function(){ resolve(value) }, ms) }) } MyPromise.resolve = function(value) { return new MyPromise(function(resolve, reject){ resolve(value) }) } MyPromise.reject = function(value) { return new MyPromise(function(resolve, reject){ reject(value) }) } MyPromise.all = function(promises) { return new MyPromise(function(resolve, reject) { var result = [] function resolver(index) { return function(val) { result.push(val) while(--index) { resolve(result) } } } function rejecter(reason) { reject(reason) } for (var i = 0; i < promises.length; i++) { promises[i].then(resolver(i), rejecter) } }) } MyPromise.race = function(promises) { return new MyPromise(resolve, reject) { function resolver(val) { resolve(val) } function rejecter(reason) { reject(reason) } for (var i = 0; i < promises.length; i++) { promises[i].then(resolver, rejecter) } } }遵循Promise A+ 規(guī)范的 Promise 實現(xiàn) Promise A+ then 規(guī)范 Promise決議解決過程
這個是將promise和一個值x作為輸入的一個抽象操作。如果這個x是支持then的,他會嘗試讓promise接受x的狀態(tài);否則,他會用x的值來fullfill這個promise。運行這樣一個東西,遵循以下的步驟 2.3.1 如果promise和x指向同一個對象,則reject這個promise使用TypeError。 2.3.2 如果x是一個promise,接受他的狀態(tài) 2.3.2.1 如果x在pending,promise必須等待x的狀態(tài)改變 2.3.2.2 如果x被fullfill,那么fullfill這個promise使用同一個value 2.3.2.3 如果x被reject,那么reject這個promise使用同一個理由 2.3.3 如果x是一個對象或者是個方法 2.3.3.1 then = x.then 2.3.3.2 如果x.then返回了錯誤,則reject這個promise使用錯誤。 2.3.3.3 如果then是一個function,使用x為this,resolvePromise為一參,rejectPromise為二參, 2.3.3.3.1 如果resolvePromise被一個值y調用,那么運行[[Resolve]](promise, y) 2.3.3.3.2 如果rejectPromise被reason r,使用r來reject這個promise 2.3.3.3.3 如果resolvePromise和rejectPromise都被調用了,那么第一個被調用的有優(yōu)先權,其他的beihulue 2.3.3.3.4 如果調用then方法得到了exception,如果上面的方法被調用了,則忽略,否則reject這個promise 2.3.3.4 如果then方法不是function,那么fullfill這個promise使用x 2.3.4 如果x不是一個對象或者方法,那么fullfill這個promise使用x 如果promise產生了環(huán)形的嵌套,比如[[Resolve]](promise, thenable)最終喚起了[[Resolve]](promise, thenable),那么實現(xiàn)建議且并不強求來發(fā)現(xiàn)這種循環(huán),并且reject這個promise使用一個TypeError。代碼實現(xiàn)
const PENDING = "pending"; const FULFILLED = "fulfilled"; const REJECTED = "rejected"; function Promise(executor) { let self = this; self.status = PENDING; self.onFulfilled = [];//成功的回調 self.onRejected = []; //失敗的回調 //PromiseA+ 2.1 function resolve(value) { if (self.status === PENDING) { self.status = FULFILLED; self.value = value; self.onFulfilled.forEach(fn => fn());//PromiseA+ 2.2.6.1 } } function reject(reason) { if (self.status === PENDING) { self.status = REJECTED; self.reason = reason; self.onRejected.forEach(fn => fn());//PromiseA+ 2.2.6.2 } } try { executor(resolve, reject); } catch (e) { reject(e); } } Promise.prototype.then = function (onFulfilled, onRejected) { //PromiseA+ 2.2.1 / PromiseA+ 2.2.5 / PromiseA+ 2.2.7.3 / PromiseA+ 2.2.7.4 onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value; onRejected = typeof onRejected === "function" ? onRejected : reason => { throw reason }; let self = this; //PromiseA+ 2.2.7 let promise2 = new Promise((resolve, reject) => { if (self.status === FULFILLED) { //PromiseA+ 2.2.2 //PromiseA+ 2.2.4 --- setTimeout setTimeout(() => { try { //PromiseA+ 2.2.7.1 let x = onFulfilled(self.value); resolvePromise(promise2, x, resolve, reject); } catch (e) { //PromiseA+ 2.2.7.2 reject(e); } }); } else if (self.status === REJECTED) { //PromiseA+ 2.2.3 setTimeout(() => { try { let x = onRejected(self.reason); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }); } else if (self.status === PENDING) { self.onFulfilled.push(() => { setTimeout(() => { try { let x = onFulfilled(self.value); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }); }); self.onRejected.push(() => { setTimeout(() => { try { let x = onRejected(self.reason); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }); }); } }); return promise2; } function resolvePromise(promise2, x, resolve, reject) { let self = this; //PromiseA+ 2.3.1 if (promise2 === x) { reject(new TypeError("Chaining cycle")); } if (x && typeof x === "object" || typeof x === "function") { let used; //PromiseA+2.3.3.3.3 只能調用一次 try { let then = x.then; if (typeof then === "function") { //PromiseA+2.3.3 then.call(x, (y) => { //PromiseA+2.3.3.1 if (used) return; used = true; resolvePromise(promise2, y, resolve, reject); }, (r) => { //PromiseA+2.3.3.2 if (used) return; used = true; reject(r); }); }else{ //PromiseA+2.3.3.4 if (used) return; used = true; resolve(x); } } catch (e) { //PromiseA+ 2.3.3.2 if (used) return; used = true; reject(e); } } else { //PromiseA+ 2.3.3.4 resolve(x); } } module.exports = Promise;
resolvePromise 函數(shù)即為根據(jù)x的值來決定promise2的狀態(tài)的函數(shù),也即標準中的Promise Resolution Procedure;x為promise2 = promise1.then(onResolved, onRejected)里onResolved/onRejected的返回值,resolve和reject實際上是promise2的executor的兩個實參,因為很難掛在其它的地方,所以一并傳進來。
promise 總結Promise的then方法回調是異步,構造函數(shù)內是同步?!緝韧猱悺?/p>
Promise狀態(tài)一旦改變,無法在發(fā)生變更。 pending -> fulfilled、 pending -> rejected
Promise的then方法的參數(shù)期望是函數(shù),傳入非函數(shù)則會發(fā)生值穿透。
promise 的.then或者.catch可以被調用多次,但這里 Promise 構造函數(shù)只執(zhí)行一次?;蛘哒f promise 內部狀態(tài)一經(jīng)改變,并且有了一個值,那么后續(xù)每次調用.then 或者.catch都會直接拿到該值。
promise 的.then或者.catch返回promise對象【catch方法是then(null, function(error){})的語法糖/省略寫法】
如果調用 then 時,promise已經(jīng)成功,則執(zhí)行 onFulfilled,并將promise的值作為參數(shù)傳遞進去。如果promise已經(jīng)失敗,那么執(zhí)行 onRejected, 并將 promise 失敗的原因作為參數(shù)傳遞進去。如果promise的狀態(tài)是pending,需要將onFulfilled和onRejected函數(shù)存放起來,等待狀態(tài)確定后,再依次將對應的函數(shù)執(zhí)行(發(fā)布訂閱)
then 的參數(shù) onFulfilled 和 onRejected 可以缺省
promise 可以then多次,promise 的then 方法返回一個 promise
如果 then 返回的是一個結果,那么就會把這個結果作為參數(shù),傳遞給下一個then的成功的回調(onFulfilled)
如果 then 中拋出了異常,那么就會把這個異常作為參數(shù),傳遞給下一個then的失敗的回調(onRejected)
如果 then 返回的是一個promise,那么需要等這個promise,那么會等這個promise執(zhí)行完,promise如果成功,就走下一個then的成功,如果失敗,就走下一個then的失敗
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://m.hztianpu.com/yun/103996.html
摘要:本身就是的語法糖。類似于后面代碼會等內部代碼全部完成后再執(zhí)行打印結果操作符用于等待一個對象。它只能在異步函數(shù)中使用。參考附在版本位中是可以直接使用的。持續(xù)更新中來點顆吧 async await本身就是promise + generator的語法糖。 本文主要講述以下內容 async awiat 實質 async await 主要特性 async await 實質 下面使用 pro...
摘要:本身就是的語法糖。類似于后面代碼會等內部代碼全部完成后再執(zhí)行打印結果操作符用于等待一個對象。它只能在異步函數(shù)中使用。參考附在版本位中是可以直接使用的。持續(xù)更新中來點顆吧 async await本身就是promise + generator的語法糖。 本文主要講述以下內容 async awiat 實質 async await 主要特性 async await 實質 下面使用 pro...
摘要:本身就是的語法糖。類似于后面代碼會等內部代碼全部完成后再執(zhí)行打印結果操作符用于等待一個對象。它只能在異步函數(shù)中使用。參考附在版本位中是可以直接使用的。持續(xù)更新中來點顆吧 async await本身就是promise + generator的語法糖。 本文主要講述以下內容 async awiat 實質 async await 主要特性 async await 實質 下面使用 pro...
摘要:現(xiàn)在不會用都不好意思說自己是前端,為什么火起來,一句話解決了回調嵌套和執(zhí)行順序問題最重要的我感覺是解決順序問題。 現(xiàn)在不會用Promise都不好意思說自己是前端,Promise為什么火起來,一句話解決了回調嵌套和執(zhí)行順序問題最重要的我感覺是解決順序問題。 不過開始寫之前我們先看看,promise怎么解決問題,怎么用。列舉一個順序加載圖片demo: //需求 加載三張圖片 img1,im...
閱讀 2013·2023-04-26 01:44
閱讀 1342·2021-11-12 10:34
閱讀 1696·2021-09-09 09:33
閱讀 1816·2019-08-30 15:44
閱讀 2959·2019-08-30 13:49
閱讀 2268·2019-08-29 15:26
閱讀 1004·2019-08-26 13:30
閱讀 1485·2019-08-23 18:15