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() // å®æä¸ä¸ªä»»å¡å³å¯ï¼ç¸å½äº æã(è¿ä¸ªç»å¸¸ç¨å¨ä¸äºå¾çæ¯è¾å¤çç½ç«)