摘要:调用初始的的方法,将匿名函数和匿名函数添加到原始的回调列表。当的状态发生了改变,相关的回调函数会被执行,上面注册的是的和方法作为的回调函数,那么的函数会在的状态改变后被执行,那么的状态就发生了改变。
Promise实现代码分析
全是去尝试理解别人是怎么实现promise的,感觉下面这两个链接的Promise实现比较好。
实现1 实现2
实现2的配图以及讲解更细致一点,如果能跟着作者举的例子走一遍,应该能够理解为什么可以then().then().then(),以及理解为啥resolve(Promise)的状态为啥是由参数的promise的状态来决定的,也能理解resolve(value)的参数是如何传递给后续的通过then注册的function的。但是30分钟有点少,犹犹豫豫,纠结得看了好久。
相对而言,实现1的较为完整,实现2的某些东西只是提到了,但是没提供实现。比如resolve/reject都只能调用一次。
实现1
function doResolve(fn, onFulfilled, onRejected) { var done = false; try { fn(function (value) { if (done) return done = true onFulfilled(value) }, function (reason) { if (done) return done = true onRejected(reason) }) } catch (ex) { if (done) return done = true onRejected(ex) } }
var promise = new Promise(fn);
fn是创建promise传入的参数,它是一个function,在创建Promise的过程中需要被调用。
这个fn有两个参数,都是function,前面一个是在fn按照得到了正常的结果之后调用的,那么then注册的onfulfilled的方法就会在完成之后调用。另外一个就是fn遇到了意料之外的结果,相应的就会调用then注册的onrejected方法。
doResolve的方法就是让fn只能调用一次resolve或者一次reject方法,即只能改变promise的状态一次。
this.done = function (onFulfilled, onRejected) { // ensure we are always asynchronous setTimeout(function () { handle({ onFulfilled: onFulfilled, onRejected: onRejected }); }, 0); }
这个done方法主要是把注册的方法加入到自己这个Promise的回调列表里面。同时为了保证通过then方法注册的function,都要在resolve之后才能调用,用了setTimeout来保证这一点(实现2是这么说的,虽然是在不同的地方用setTimeout)。
function handle(handler) { if (state === PENDING) { handlers.push(handler); } else { if (state === FULFILLED && typeof handler.onFulfilled === "function") { handler.onFulfilled(value); } if (state === REJECTED && typeof handler.onRejected === "function") { handler.onRejected(value); } } }
handle这个方法,比实现2的方法要简单一点,因为相关的逻辑在then方法里面体现了。
这个其实就是通过当前的状态来判断是把回调加到回调列表里面还是直接执行fulfill或者reject方法。
this.then = function (onFulfilled, onRejected) { var self = this; return new Promise(function (resolve, reject) { return self.done(function (result) { if (typeof onFulfilled === "function") { try { return resolve(onFulfilled(result)); } catch (ex) { return reject(ex); } } else { return resolve(result); } }, function (error) { if (typeof onRejected === "function") { try { return resolve(onRejected(error)); } catch (ex) { return reject(ex); } } else { return reject(error); } }); }); }
then方法很关键,也较难懂。这边写的有点多,感觉实现2写的好一点,把这些逻辑放在另外一个位置而不是在构建新promise的过程中。单纯从理解上来讲。
首先分析下每个参数的意思。
this.then = function (onFulfilled, onRejected)这里面的onFulfilled,onRejected是then方法给当前这个Promise注册的两个方法。
return new Promise(function (resolve, reject)这里的return new Promise就是为了新建一个Promise从而可以进行链式then方法的调用. then(fn1,fn2).then(fn3,fn4)=>var promise = then(fn1,fn2);
promise.then(fn3,fn4);resolve和reject则是这个新生成的promise的状态设置方法。
self.done(function (result),function(error));调用初始的promise的done方法,将匿名函数function(result)和匿名函数function(error)添加到原始promise的回调列表。
然后再来看看匿名函数function(result)应该怎么执行。
function (result) { if (typeof onFulfilled === "function") { try { return resolve(onFulfilled(result)); } catch (ex) { return reject(ex); } } else { return resolve(result); } }
如果then方法注册的是function,那么肯定是要用这个function去执行,onFulfilled(result)就是这个作用。
resolve是新产生的resolve的状态设定器。执行完onFulfilled(result),产生的结果假如是newresult再交给resolve去执行。新的promise的resolve方法就会将新的promise的状态设置成fulfilled,那么新promise的then方法就可以在注册完后续的方法后接着执行。resolve(newresult)就将onFulfilled(result)产生的结果
传递给了后续的then方法注册的function。
function getThen(value) { var t = typeof value; if (value && (t === "object" || t === "function")) { var then = value.then; if (typeof then === "function") { return then; } } return null; }
getThen方法是为了查看这个结果是不是一个Promise或者说是含有then方法的Object.如果有then方法,就把then方法返回,否则就返回null
function resolve(result) { try { var then = getThen(result); if (then) { doResolve(then.bind(result), resolve, reject) return } fulfill(result); } catch (e) { reject(e); } }
resolve这个方法可以处理参数是正常数值或者是Promise。根据Promise的使用说明,A promise resolve(Promise B),那么Promise A的状态会在Promise B的状态发生变化(变成fulfilled或者rejected)才会变化。首先用getThen来确定给定的参数是不是有then函数的Object,如果不是,那么就是单纯的将值赋给Promise A的内部变量value,后续回调函数就可以用这个value作为参数,这也是为什么resolve能把其参数传给通过then注册的回调函数。那么如果是有then函数的object呢,首先getThen返回了那个object的then函数。
然后then.bind(result)是让then函数的调用在拥有这个then函数的object里面执行,也就是resolve的参数result。然后doResolve实际上也就是执行了result这个promise的then方法。只不过注册的两个方法是当前这个
promise的resolve和reject方法。
所以实际上执行的是promiseB.then(resolve,reject);根据我们前面对then方法的分析可以知道。当promiseB的状态发生了改变,相关的回调函数会被执行,上面注册的是Promise A的resolve和reject方法作为promiseB的回调函数,那么Promise A的resolve/reject函数会在promiseB的状态改变后被执行,那么PromiseA的状态就发生了改变。同时PromiseB中产生的结果也会通过resolve这个函数传给Promise A.
这个其实看实现2的handle方法以及then如何调用handle方法会更容易理解一点。而且作者画了个很详细的图。
还忘了一点,就是为啥then方法前面有this。后来我觉得无所谓,然后把this去掉了,结果在调用的时候没法调用这个then函数。this.then应该是接口吧。虽然当时在W3Cschool上学习原型构造的时候很认真,但是还是忽略了习以为常的this。直到有的function有this,有的没有,才感觉有点奇怪,我自己写的时候怎么判断要不要加this啊。
大致就是这样。匿名函数的调用,传入的参数以及实际使用的参数,会引起很多干扰,说到底还是不太熟悉javascript的调用和特色吧。但是应该有更好的书写方式吧。所说的东西只是自以为是的理解,实在很难确信自己是对的。因为觉得是对的,所以就会朝那个方向去靠,有点像老师解答试卷的标准答案一样,即使标准答案是错的。网上还是充斥着很多不怎么准确的东西的,还是按照自己的意愿、想法去测试下。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/90298.html
摘要:遗传算法物竞天择,适者生存,遗传算法就是借鉴生物体自然选择和自然遗传机制的随机搜索算法。随机生成的基因适应度的最大值随机生成,适应度函数计算种群中所有对象的适应度及总和,并对超出的基因进行惩罚。 此为《算法的乐趣》读书笔记,我用javascript(ES6)重新实现算法。 遗传算法 物竞天择,适者生存,遗传算法就是借鉴生物体自然选择和自然遗传机制的随机搜索算法。算法的关键点有:基因的选...
摘要:强烈推荐上值得前端学习的数据结构与算法项目,包含图的演示过程与视频讲解。该仓库包含了多种基于的算法与数据结构,提供进一步阅读的解释和链接。数据结构和算法必知必会的个代码实现。 showImg(https://segmentfault.com/img/bVbvpYZ); 前言 算法为王。想学好前端,先练好内功,内功不行,就算招式练的再花哨,终究成不了高手;只有内功深厚者,前端之路才会走得...
摘要:笔者写的数据结构与算法之美系列用的语言是,旨在入门数据结构与算法和方便以后复习。这应该是目前较为简单的十大经典排序算法的文章讲解了吧。比如原本在的前面,而,排序之后,在的后面十大经典排序算法冒泡排序思想冒泡排序只会操作相邻的两个数据。 showImg(https://segmentfault.com/img/bVbvHet); 1. 前言 算法为王。想学好前端,先练好内功,内功不行,就...
摘要:回顾选择排序,插入排序,冒泡排序,快速排序,希尔排序,归并排序,堆排序以及如何计算时间复杂度学习文章同学的描述数据结构等同学的十大经典算法本文代码也上传到了排序算法回顾。但希尔排序是非稳定排序算法。 回顾选择排序,插入排序,冒泡排序,快速排序,希尔排序,归并排序,堆排序以及如何计算时间复杂度学习文章:hahda同学的javascript描述数据结构、hustcc等同学的十大经典算法 ...
摘要:之所以把计数排序桶排序基数排序放在一起比较,是因为它们的平均时间复杂度都为。动画计数排序思想找出待排序的数组中最大和最小的元素。桶排序计数排序能派上用场吗手机号码有位,范围太大,显然不适合用这两种排序算法。 showImg(https://segmentfault.com/img/bVbuF9e?w=900&h=500); 1. 前言 算法为王。 想学好前端,先练好内功,只有内功深厚者...
摘要:之所以把冒泡排序选择排序插入排序放在一起比较,是因为它们的平均时间复杂度都为。其中,冒泡排序就是原地排序算法。所以冒泡排序是稳定的排序算法。选择排序思路选择排序算法的实现思路有点类似插入排序,也分已排序区间和未排序区间。 showImg(https://segmentfault.com/img/bVbuvnj?w=900&h=250); 1. 前言 算法为王。 想学好前端,先练好内功,...
阅读 865·2021-09-29 09:35
阅读 1229·2021-09-28 09:36
阅读 1493·2021-09-24 10:38
阅读 1038·2021-09-10 11:18
阅读 611·2019-08-30 15:54
阅读 2482·2019-08-30 13:22
阅读 1938·2019-08-30 11:14
阅读 673·2019-08-29 12:35