发布网友 发布时间:2024-10-24 01:02
共1个回答
热心网友 时间:2024-11-06 19:05
Promise超详细源码解读
说到Promise,相信大家在日常开发中都经常使用到,它是我们异步操作中必不可少的一部分,可以让代码看起来变得更好理解;
我曾在技术社区看过许多关于promise底层原理的文章,大概原理明白,这次,我准备系统的分析实现源码并记录下来,本文将一行行代码去分析最后附加流程图和总结,希望这能对你有帮助;
promise的实现库有这么多,接下来我们以github的promiseployfill为例,想看完整实现代码的在这里;
最基础用法我们先想象一下promise最常见的使用方式,大概像这样
new?Promise((resolve,reject)?=>?{????setTimeout(?()?=>?resolve('result'),1000)}).then(?(value)?=>?{????console.log(?value?)})首先是newPromise(),那么Promise肯定是一个定好的构造函数,果然。
PromiseFuncfunction?Promise(fn)?{??if?(!(this?instanceof?Promise))????throw?new?TypeError('Promises?must?be?constructed?via?new');??if?(typeof?fn?!==?'function')?throw?new?TypeError('not?a?function');??this._state?=?0;??this._handled?=?false;??this._value?=?undefined;??this._deferreds?=?[];??doResolve(fn,?this);}可以看到这里大致了必须要使用new操作符调用Promise,还有我们的参数必须是函数类型的;
初始化属性(_state,__handled,_value,_deferreds),这些属性后面要用到;
先看一下_state
/**?内部状态码???*?0:?pending,当前Promise正在执行中,默认值???*?1:?fulfilled,?执行了resolve函数,且参数_value不是期约,即_value?instanceof?Promise?===?false???*?2:?rejected,执行了reject函数???*?3:?fulfilled,执行了resolve函数,且参数_value是期约,即_value?instanceof?Promise?===?true*/_value为存放我们最终resolve或reject的结果
_deferreds缓存then方法执行后生成的handle实例对象,把传入的回调缓存成handle实例对象的属性
调用doResolve(fn,this);
可以看到我们把fn和this传递给了doResolve执行,接着看看doResolve;
doResolveFuncfunction?doResolve(fn,?self)?{??var?done?=?false;??try?{????fn(??????function(value)?{????????if?(done)?return;????????done?=?true;????????resolve(self,?value);??????},??????function(reason)?{????????if?(done)?return;????????done?=?true;????????reject(self,?reason);??????}????);??}?catch?(ex)?{????if?(done)?return;????done?=?true;????reject(self,?ex);??}}可以看到doResolve很简单,它直接调用了我们newPromise(fn)传递进去的fn,把两个匿名函数传递给了resolve,reject给我们在外部操作完成后调用,然后如果有出错会直接帮我们调用reject;
//?可以看回我们new?Promise(fn)传递进去的fn(resolve,reject)?=>?{????setTimeout(?()?=>?resolve('result'),1000)}执行fn,我们的setTimeout在1000ms后调用了resolve('result');
传递给fn的resolve是
function(value)?{????if?(done)?return;????done?=?true;????resolve(self,?value);}这里的done实际上是为了防止我们多次调用resolve,只有第一次生效吧;
由于我们是异步调用resolve的,执行完setTimeout之后就会执行then,1000ms后才会调用resolve[我们往thenFunc里面看](#thenFunc)
由于我们fn里只调用了resolve,接下来我们直接看resolve
resolveFuncfunction?resolve(self,?newValue)?{??try?{????if?(newValue?===?self)??????throw?new?TypeError('A?promise?cannot?be?resolved?with?itself.');????if?(??????newValue?&&??????(typeof?newValue?===?'object'?||?typeof?newValue?===?'function')????)?{??????var?then?=?newValue.then;??????if?(newValue?instanceof?Promise)?{????????self._state?=?3;????????self._value?=?newValue;????????finale(self);????????return;??????}?else?if?(typeof?then?===?'function')?{????????doResolve(bind(then,?newValue),?self);????????return;??????}????}????self._state?=?1;????self._value?=?newValue;????finale(self);??}?catch?(e)?{????reject(self,?e);??}}resolve主要是校验我们newValue的类型,我们的newValue是'result',自然是string
self是通过PromiseFunc->doResolveFunc,传递下去的this,也就是首先判断的是newValue不能是newPromise的this本身
newValue是object||function类型
newValue是Promise实例,像我们上面说的_state会是3(),_把newValue赋值给我们最终resolve的结果,并执行finale(self);
newValue.then是函数,会重新执行doResolve,不会执行finale;
newValue不是Promise实例,newValue.then也不是函数,_state会是1(),把newValue赋值给我们最终resolve的结果,并执行finale(self);
很显然,我们的例子里resolve的类型效验会执行以上list->3,我们看看finale
finaleFuncfunction?finale(self)?{??if?(self._state?===?2?&&?self._deferreds.length?===?0)?{????Promise._immediateFn(function()?{??????if?(!self._handled)?{????????Promise._unhandledRejectionFn(self._value);??????}????});??}??for?(var?i?=?0,?len?=?self._deferreds.length;?i?<?len;?i++)?{????handle(self,?self._deferreds[i]);??}??self._deferreds?=?null;}_state为1,finale代码会执行
for?(var?i?=?0,?len?=?self._deferreds.length;?i?<?len;?i++)?{????handle(self,?self._deferreds[i]);}self._deferreds?=?null;?呃...循环了thenFunc->handleFuncpush进去的deferred,又重新拿着deferred执行handleFunc??
这里跟我们在thenFunc的调用方式好像没有什么不同,只是我们调用完resolveFunc后_state和_value就有值了
self._state?=?1;self._value?=?newValue;[去看handleFunc](#handleFunc)
thenFuncfunction?Promise(fn)?{??if?(!(this?instanceof?Promise))????throw?new?TypeError('Promises?must?be?constructed?via?new');??if?(typeof?fn?!==?'function')?throw?new?TypeError('not?a?function');??this._state?=?0;??this._handled?=?false;??this._value?=?undefined;??this._deferreds?=?[];??doResolve(fn,?this);}0可以看到then是在Promise原型链上的方法
noopnoop是一个空函数,这里的this.constructor即Object.constructor;
即newObject.constructor(functionnoop(){});
?...赶紧去控制台试试看;
function?Promise(fn)?{??if?(!(this?instanceof?Promise))????throw?new?TypeError('Promises?must?be?constructed?via?new');??if?(typeof?fn?!==?'function')?throw?new?TypeError('not?a?function');??this._state?=?0;??this._handled?=?false;??this._value?=?undefined;??this._deferreds?=?[];??doResolve(fn,?this);}1呃...实际上我们得到一个包装好参数的函数,把它赋值为prom
handle首先handle(this,newHandler(onFulfilled,onRejected,prom));
newHandler(onFulfilled,onRejected,prom)
function?Promise(fn)?{??if?(!(this?instanceof?Promise))????throw?new?TypeError('Promises?must?be?constructed?via?new');??if?(typeof?fn?!==?'function')?throw?new?TypeError('not?a?function');??this._state?=?0;??this._handled?=?false;??this._value?=?undefined;??this._deferreds?=?[];??doResolve(fn,?this);}2这个函数还是挺好理解的,newHandler创建一个handler对象,这里的this也就是handler;
handler下有三个属性,onFulfilled,onRejected是我们调用promise.then(onFulfilled,onRejected)是传递进来的,promise也就是我们刚刚赋值的prom函数
然后就是handle(this,handler),当前的的this为当前的newpromise对象,handler为刚刚的newHandler实例对象
handleFuncfunction?Promise(fn)?{??if?(!(this?instanceof?Promise))????throw?new?TypeError('Promises?must?be?constructed?via?new');??if?(typeof?fn?!==?'function')?throw?new?TypeError('not?a?function');??this._state?=?0;??this._handled?=?false;??this._value?=?undefined;??this._deferreds?=?[];??doResolve(fn,?this);}3如果是thenFunc调用的handleFunc,我们到当前为止并没有改变_state,即为0,直接self._deferreds.push(deferred)后return了
function?Promise(fn)?{??if?(!(this?instanceof?Promise))????throw?new?TypeError('Promises?must?be?constructed?via?new');??if?(typeof?fn?!==?'function')?throw?new?TypeError('not?a?function');??this._state?=?0;??this._handled?=?false;??this._value?=?undefined;??this._deferreds?=?[];??doResolve(fn,?this);}4到这里为止,我们的thenFunc一系列的调用就完毕了,1000ms后会调用resolve,[我们看回resolveFunc](#resolveFunc)
如果是从resolveFunc->finaleFunc调用的handleFunc,那么_state和_value就有值了,在我们例子里_state为1,_value为'result',会执行
function?Promise(fn)?{??if?(!(this?instanceof?Promise))????throw?new?TypeError('Promises?must?be?constructed?via?new');??if?(typeof?fn?!==?'function')?throw?new?TypeError('not?a?function');??this._state?=?0;??this._handled?=?false;??this._value?=?undefined;??this._deferreds?=?[];??doResolve(fn,?this);}5Promise._immediateFn的参数会在不久后执行,我们先看内容,后面再详细看这个
根据_state判断调用deferred.onFulfilled||deferred.onRejected,我们说_state有四个值,忘记的可以回去上面看看,代码执行到这里state的值只有1||2;
deferred为我们调用thenFunc->handle->push进去的handle实例化对象;
到ret=cb(self._value);为止,我们整个newPromise((resolve,reject)=>{}).then(()=>{})就走完了,可以看到是通过_state值去判断调用我们thenFunc传递进去的两个函数的
回到immediateFnfunction?Promise(fn)?{??if?(!(this?instanceof?Promise))????throw?new?TypeError('Promises?must?be?constructed?via?new');??if?(typeof?fn?!==?'function')?throw?new?TypeError('not?a?function');??this._state?=?0;??this._handled?=?false;??this._value?=?undefined;??this._deferreds?=?[];??doResolve(fn,?this);}6呃...阿这..?Promise._immediateFn实际上是使用setTimeout执行的,由于即使设定timeout为0,setTimeout也会有一定的延时,这样哪怕我们在fn中直接执行了resolveFunc,执行顺序也会比thenFunc晚;
重新梳理执行流程图Promise.all实现提问环节后续会公布答案和原理
console.log的顺序是什么?为什么??
function?Promise(fn)?{??if?(!(this?instanceof?Promise))????throw?new?TypeError('Promises?must?be?constructed?via?new');??if?(typeof?fn?!==?'function')?throw?new?TypeError('not?a?function');??this._state?=?0;??this._handled?=?false;??this._value?=?undefined;??this._deferreds?=?[];??doResolve(fn,?this);}7function?Promise(fn)?{??if?(!(this?instanceof?Promise))????throw?new?TypeError('Promises?must?be?constructed?via?new');??if?(typeof?fn?!==?'function')?throw?new?TypeError('not?a?function');??this._state?=?0;??this._handled?=?false;??this._value?=?undefined;??this._deferreds?=?[];??doResolve(fn,?this);}8以下Promise.all的结果是什么??
function?Promise(fn)?{??if?(!(this?instanceof?Promise))????throw?new?TypeError('Promises?must?be?constructed?via?new');??if?(typeof?fn?!==?'function')?throw?new?TypeError('not?a?function');??this._state?=?0;??this._handled?=?false;??this._value?=?undefined;??this._deferreds?=?[];??doResolve(fn,?this);}9持续更新中...
原文:https://juejin.cn/post/7095619778823340046