1.从规范面解读:Promises/A+规范与浏览器Promise规范有何区别?
2.利用ES6的Promise.all实现至少请求多长时间的实例
3.JSç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的成功值valuePromises/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与microTaskPromises/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是外汇 源码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() // å®æä¸ä¸ªä»»å¡å³å¯ï¼ç¸å½äº æã(è¿ä¸ªç»å¸¸ç¨å¨ä¸äºå¾çæ¯è¾å¤çç½ç«)