Promise超详细源码解读

发布网友 发布时间:2024-10-24 01:02

我来回答

1个回答

热心网友 时间:2024-10-24 05: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原型链上的方法

noop

noop是一个空函数,这里的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);}5

Promise._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

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com