皮皮网

皮皮网

【仿飞猪源码】【潮汕麻将源码】【爱心银行源码】es6 promise 源码

时间:2024-12-25 14:44:42 分类:热点

1.从规范面解读:Promises/A+规范与浏览器Promise规范有何区别?
2.利用ES6的Promise.all实现至少请求多长时间的实例
3.JS的Promise兄弟

es6 promise 源码

从规范面解读:Promises/A+规范与浏览器Promise规范有何区别?

       前言

       Promise是一种优秀的异步解决方案,其原生实现更是面试中的爆点,提到Promise实现,我们首先会想起Promises/A+规范,大多数教程中都是按照Promises/A+规范来实现Promise。

       小包也是仿飞猪源码Promises/A+圣经的执行者之一,但小包心中一直有个好奇,遵循Promises/A+规范实现的Promise与ES6-Promise能有什么区别呐?

       文章中的测试代码选取小包基于Promises/A+规范实现的原生Promise

       学习本文,你能收获:

       进一步完善原生Promise的实现

       更进一步理解Promise与microTask之间的关系

promise的成功值value

       Promises/A+规范只提供了value的定义,并没有详细说明如何处理不同类型的value值:

       “value”isanylegalJavaScriptvalue(including?undefined,athenable,orapromise).value可以是任意合法的JavaScript值,包括undefined、具备then接口的对象或者promise

       但ECMAScript规范对不同类型的value做了细致的处理。

       红框部分我们可以看出,ES6规范会根据resolution(相当于Promises/A+规范中的潮汕麻将源码value)类型选取不同的执行方案。

       判断resolution是否为Object,如果不是,直接执行FulfillPromise

       如果是Object,试探是否存在then接口

       判断then是否可执行(abruptcompletion可以理解为非正常值)

       如果then可执行,将then方法放入事件队列中。

       PromiseResolveThenableJob:该job使用传入的thenable的then方法来解决promise。

       一句话总结上面的过程:如果value值为可thenable对象或者promise,ES6会采用该thenable的状态。

       小包举个栗子:

const?p?=?new?Promise((resolve)?=>?{ resolve(1);});const?p1?=?new?Promise((resolve)?=>?{ resolve(p);});p1.then((d)?=>?console.log(d));

       p1接收的成功值value为Promisep,p状态为fulfilled,这种情况下ES6中会采取p的状态及value,因此最终打印1。

       我们将p更换为具备thenable对象,爱心银行源码结果也是类似的。

//?类?promise?对象const?p1?=?{ a:?1,then(onFulfilled,?onReject)?{ onFulfilled(this.a);},};const?p2?=?new?Promise((resolve)?=>?{ resolve(p1);});//?1p2.then((d)?=>?console.log(d));

       Promises/A+没有对此进行规范,因此当传入的value为thenable对象时,会原封不动的输出。

       那我们应该如何完善这部分代码呐?我们需要对value值进行解析,如果value可thenable,则采纳他的状态和值,递归进行上述步骤,直至value不可thenable。(这里与resolvePromise部分递归解析onFulfilled函数的返回值是类似的)

const?resolve?=?(value)?=>?{ if?(typeof?value?===?"object"?&&?value?!=?null)?{ try?{ const?then?=?value.then;if?(typeof?then?===?"function")?{ return?then.call(value,?resolve,?reject);}}?catch?(e)?{ return?reject(e);}}if?(this.status?===?PENDING)?{ this.value?=?value;this.status?=?FULFILLED;this.onFulfilledCallbacks.forEach((cb)?=>?cb(this.value));}};Promise与microTask

       Promises/A+规范中其实并没有将Promise对象与microTask挂钩,规范是这么说的:

       Here“platformcode”meansengine,environment,andpromiseimplementationcode.Inpractice,thisrequirementensuresthat?onFulfilled?and?onRejected?executeasynchronously,aftertheeventloopturninwhich?then?iscalled,andwithafreshstack.Thiscanbeimplementedwitheithera“macro-task”mechanismsuchas?setTimeout?or?setImmediate,orwitha“micro-task”mechanismsuchas?MutationObserver?or?process.nextTick.Sincethepromiseimplementationisconsideredplatformcode,itmayitselfcontainatask-schedulingqueueor“trampoline”inwhichthehandlersarecalled.

       Promises/A+规范中表示then方法可以通过setTimeout或setImediate等宏任务机制实现,也可以通过MutationObserver或process.nextTick等微任务机制实现。

       但经过大量面试题洗礼的人人秀源码我们知道浏览器中的Promise.then典型的微任务。既然都学到这里了,小包索性就打破砂锅问到底,找到Promise与microTask挂钩的根源。

谁规定了Promise是microTask

       标准读起来属实有些无聊,但好在小包找到了最终的答案。

       首先小包先入为主的以为,Promise的详细规定应该都位于ECMAScript制定的规范中,但当小包进入标准后,全局搜索micro,竟然只搜索到三个Microsoft。讲实话,小包是震惊的,ECMAScript并没有规定Promise是app 商店 源码microTask。

       ECMAScript规范中,最接近的是下面两段表达:

       The?host-defined?abstractoperationHostEnqueuePromiseJobtakesarguments?job?(a?Job?AbstractClosure)and?realm?(a?RealmRecord?or?null)andreturns?unused.Itschedules?job?tobeperformedatsomefuturetime.The?AbstractClosures?usedwiththisalgorithmareintendedtoberelatedtothehandlingofPromises,orotherwise,tobescheduledwithequalprioritytoPromisehandlingoperations.

       JobsarescheduledforexecutionbyECMAScripthostenvironments.ThisspecificationdescribesthehosthookHostEnqueuePromiseJobtoscheduleonekindofjob;hostsmaydefineadditionalabstractoperationswhichschedulejobs.SuchoperationsacceptaJobAbstractClosureastheparameterandscheduleittobeperformedatsomefuturetime.Theirimplementationsmustconformtothefollowingrequirements:

       上面两句话意思大约是:ECMAScript中将Promise看作一个job(作业),HostEnqueuePromiseJob是用来调度Promise作业的方法,这个方法会在未来某个时间段执行,具体执行与Promise的处理函数或者与Promise处理操作相同的优先级有关。

       那何处将Promise规定为microTask呐?---HTML标准

       HTML标准中指出:

       JavaScriptcontainsan?implementation-defined?HostEnqueuePromiseJob(job,?realm)abstractoperationtoschedulePromise-relatedoperations.HTMLschedulestheseoperationsinthemicrotaskqueue.

       上述标准的最后一句话指出,HTML将在microqueue中安排这些操作。破案了,原来是HTML标准中将Promise规定为microTask。(为什么会是HTML进行规定,小包还没有探究出来)

       更深入的区别,请参考月夕大佬:V8Promise源码全面解读

后语

       我是?战场小包?,一个快速成长中的小前端,希望可以和大家一起进步。

       如果喜欢小包,可以在?掘金?关注我,同样也可以关注我的小小公众号——小包学前端。

       一路加油,冲向未来!!!

疫情早日结束人间恢复太平

       原文:/post/

利用ES6的Promise.all实现至少请求多长时间的实例

        1、背景

       我们都知道ajax请求可以加个timeout,就是最多请求多少时间,如果超过这个时间直接就报错。 这个是最多请求多长时间,我现在要做的是,最少要请求多长时间,然后才能执行后续的逻辑。

       比如,一个ajax请求 x 毫秒就执行完毕了,但我要让他至少执行1秒钟,那我们会这么想: ajax完成后 , 1. 如果x<1s, 那我们先setTimeout => 1s - x ,然后执行后续操作。 2 如果x>=1s, 那我们直接执行后续操作。 想想这可繁琐了,我们还要在前面记录一下开始时间,后面记录一下结束时间,然后才能得到x。。

       或者变量flag,ajax里面完成设置flag,setTimeout里面完成也设置flag等等等方法,都很繁琐、

       2、Solution

       现在ES6有个Promise.all,非常适合解决此类问题。直接这样 Promise.all([ajaxPromise(), waitPromise(1s)]).then(()=> 至少执行了1s) 。。

       如果说是 多个ajax(promise)按顺序执行,但总共加起来的时间至少是1s呢? 那就用一个Promise把多个ajax包起来。然后 Promise.all([ajaxPromiseAll(), waitPromise(1s)]).then(()=> 至少执行了1s) 。。

       3、 讲得很抽象,实例为证

       这个实例是这样的,微信里面有拆红包,当我们点击 _ 的时候,那个字至少会完整的 翻一翻。那个完整翻一翻的时间我们假定需要1秒钟。 如果我们直接点击开的时候,立即请求ajax,等ajax完成立即拆开红包,这里的时间 有可能不足1s,那 就不能做到完整翻一翻。 如果请求大于1s,那就让它一直翻转吧,直到完成请求。所以我们为了解决这个问题,就需要用到上面的技术。

       参考代码如下(Chrome最新版下测试):

       / ajax模拟A

       const funcA = async () =>

        new Promise(resovel => {

        setTimeout(() => {

        console.log("done A");

        resovel("func A");

        }, );

        });

       因为async和await使用起来比Promise爽,所以我采用了这两个语法糖来写,用setTimeout来模拟ajax请求, ajax模拟A和 ajax模拟B有顺序关系的,比如先检测这个人是否还有机会打开红包,然后再请求打开红包获得随机红包金额 。

       以上这篇利用ES6的Promise.all实现至少请求多长时间的实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

JS的Promise兄弟

          相信用过JS的都知道JS是单线程的,同步的函数先执行,异步的函数先加入到一个队列中等同步执行完了再执行异步函数。基于这个JS采用异步回调的方式来处理需要等待的事件,是的代码会继续执行而不用在异步处理的地方一直等待着。同时也带来一个不好的方面,如果我们有很多的回调函数, 也就是说一个回调函数里边再嵌套一个回调一层一层的嵌套,这样就很容易进入传说中的回调地狱。

           注意:异步和回调不是一个东西

          下面感受一下回调地狱代码的魅力:

          是挺有美感的但是阅读性很差,写法也让人感到无力,es6新出的promise对象已经es7的async await都可以解决这个问题,但是今天的主角是Promise。

          Promise是异步编程的一种解决方案,可以替代传统的解决方案--回调函数和事件。ES6统一了用法,并原生提供了Promise对象。作为对象,Promise有一下两个特点:(1)对象的状态不受外界影响;(2)一旦状态改变了就不会在变,也就是说任何时候Promise都只有一种状态。Promise有三种状态,分别是:Pending(进行中),Resolved(完成),Rejected (失败)。Promise从Pending状态开始,如果成功就转到成功态,并执行resolve回调函数;如果失败就转到失败状态并执行reject回调函数。

          Promise一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise 对象的状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变为 Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

          Promise构造函数接收一个函数作为参数,该函数的两个参数是resolve,reject,它们由JavaScript引擎提供。其中resolve函数的作用是当Promise对象转移到成功,调用resolve并将操作结果作为其参数传递出去;reject函数的作用是单Promise对象的状态变为失败时,将操作报出的错误作为其参数传递出去

          介绍一下Promise的api怎么使用:

           1、Promise.resolve()的作用将现有对象转为Promise对象resolved;Promise.resolve('test')==new Promise(resolve=>resolve('test'))

          2、Promise.reject()返回一个Promise对象,状态为rejected

          3、Promise.prototype.then()方法接受两个参数,第一个是成功的resolved的回调,另一个是失败rejected的回调,第二个失败的回调参数可选。并且then方法里也可以返回promise对象,这样就可以链式调用了。

           4、Promise.prototype.catch()发生错误的回调函数。

           5、Promise.all() // 所有的事都有完成,相当于 且,适合用于所有的结果都完成了才去执行then()成功的操作。

           6、Promise.race() // 完成一个任务即可,相当于 或。(这个经常用在一些图片比较多的网站)