自1996年发布以来,JS一直在稳步改进。随着ECMAScript版本的许多改进,最新版本是ES2020。JS的一个重大更新是Promises,它于2015年以ES6的名义发布。什么是Promise?MDN上对Promise的定义:Promise对象用于表示一个异步操作的最终完成(或失败)及其结果值。对于新手来说,这听起来有点太复杂了。一位外教对Promises的解释是这样的:“想象一下你是个孩子,你妈妈向你保证下周她会给你买一部新手机。”你要到下周才能知道你是否能拿到那部手机。要么你妈妈真的给你买了一部全新的手机,要么她不买是因为她不开心。这是一个承诺。一个Promise有三个状态。它们是:Pending:你不知道你能不能买到那部手机Fulfilled:我妈妈高兴,我给你买了它Rejected:我妈妈不高兴,我不会给你买的这是我听到的到目前为止,我可以理解它是最快的Promise实例。如果您还没有开始学习Promises,我建议您这样做。Promises包含几个非常有用的内置方法。今天我们主要介绍这两种方法。Promise.race()-与ES6Promise.any()一起发布-仍处于第4阶段提案中,可作为参数迭代。Promise.race(iterable)方法返回一个承诺,一旦迭代器中的承诺之一解决或拒绝,该承诺就会解决或拒绝。与Promise.any()方法不同,Promise.race()方法主要关注Promise是否被resolve,不管是resolved还是rejected。语法Promise.race(iterable)参数iterable—可迭代对象,类似于Array。可迭代对象实现Symbol.iterator方法。返回一个异步解决或拒绝的未决Promise(一旦堆栈为空),每当给定迭代中的一个承诺解决或拒绝时,将第一个承诺的值作为其值。请注意,因为参数接受一个可迭代对象,所以我们可以传递一些值,例如原始值,甚至是数组中的对象。在这种情况下,race方法将返回第一个通过的非承诺。这主要是因为该方法的行为是在值可用时(当promise被履行时)立即返回该值。此外,如果在可迭代对象中传递了一个已解析的Promise,则Promise.race()方法将解析为该值的第一个。如果传递了一个空的Iterable,则race方法将永远挂起。示例constpromise1=newPromise((resolve,reject)=>{setTimeout(resolve,500,'promise1resolved');});constpromise2=newPromise((resolve,reject)=>{setTimeout(reject,100,'promise2rejected');});constpromise3=newPromise((resolve,reject)=>{setTimeout(resolve,200,'promise3resolved')});(async()=>{try{letresult=awaitPromise.race([promise1,promise2,promise3]);console.log(result);}catch(err){console.error(err);}})();//Output-"promise2rejected"//虽然promise1和promise3可以resolve,但是promise2rejects比他们快很快。//因此Promise.race方法将拒绝使用promise2的真实用例现在,您可能想知道,我们在实践中什么时候使用Promise.race()?让我们来看看。在请求数据时显示加载动画在使用加载动画的开发中很常见。当数据响应时间长的时候,如果不使用loading动画,会看起来像是没有响应。但有时,反应太快了。当我们需要加载动画的时候,加一个很小的延迟时间,会让用户觉得我在频繁请求。为此,只需使用Promise.race()方法,如下所示。functiongetUserInfo(user){returnnewPromise((resolve,reject)=>{//haditat1500tobemoretrue-to-life,but900isbetterfortestingsetTimeout(()=>resolve("userdata!"),Math.floor(900*Math.random()));});}functionshowUserInfo(user){returngetUserInfo().then(info=>{console.log("userinfo:",info);returntrue;});}functionshowSpinner(){console.log("请稍等...")}functiontimeout(delay,result){returnnewPromise(resolve=>{setTimeout(()=>resolve(result),delay);});}Promise.race([showUserInfo(),timeout(300)]).then(displayed=>{if(!displayed)showSpinner();});**取消取消的Promise**有些情况下,我们需要取消取消Promise,这个时候也可以借用Promise.race()方法:functiontimeout(delay){letcancel;constwait=newPromise(resolve=>{consttimer=setTimeout(()=>resolve(false),delay);cancel=()=>{clearTimeout(timer);resolve(true);};});wait.cancel=cancel;returnwait;}functiondoWork(){constworkFactor=Math.floor(600*Math.random());constwork=timeout(workFactor);constresult=work.then(canceled=>{if(canceled)console.log('Workcanceled');elseconsole.log('Workdonein',workFactor,'ms');return!canceled;});result.cancel=work.cancel;返回结果;}functionattemptWork(){constwork=doWork();returnPromise.race([work,timeout(300)]).then(done=>{if(!done)work.cancel();return(done?'工作完成!':'Igaveup');});}attemptWork().then(console.log);长时间执行的批处理请求ChrisJensen有一个有趣的race()方法用例,他使用Promise.race()方法来批处理长时间运行的请求。这样,他们可以保持并行请求的数量不变。const_=require('lodash')asyncfunctionbatchRequests(options){letquery={offset:0,limit:options.limit};do{batch=awaitmodel.findAll(query);query.offset+=options.limit;if(batch.length){constpromise=doLongRequestForBatch(batch).then(()=>{//Oncecomplete,popthispromisefromourarray//sothatweknowwecanaddanotherbatchinitsplace_.remove(promises,p=>p===promise);});promises.push(promise);//一旦我们达到并发限制,waitforatleastonepromiseto//resolvebeforecontinuingtobatchoffrequestsif(promises.length>=options.concurrentBatches){awaitPromise.race(promises);}}}while(batch.length);//WaitforremainingbatchesoffinishreturnPromises.all(promises.all):100,concurrentBatches:5});Promise.any()Promise.any()接收一个Promise可迭代对象,只要有一个promise成功,就返回成功的promise。如果iterable中的承诺都没有成功(即所有承诺失败/拒绝),则返回一个失败的承诺和一个AggregateError类型的实例,它是用于将单个错误聚合在一起的Error的子类。本质上,这个方法是Promise.all()的逆函数。笔记!Promise.any()方法仍处于试验阶段,尚未得到所有浏览器的完全支持。目前在TC39Stage4语法草案中Promise.any(iterable);参数iterable—一个可迭代对象,例如Array。返回值如果传递的参数是一个空的可迭代对象,则返回一个状态为已拒绝的Promise。如果传递的参数不包含任何承诺,则返回一个被**异步解决**的承诺。在所有其他情况下,将返回一个挂起的Promise。一旦传递的iterable中的任何一个承诺解决,或者其中的所有承诺都失败(已解决/拒绝)状态,返回的承诺就会异步解决(当调用堆栈为空时)。指示此方法用于返回第一个成功的承诺。此方法会在一个promise完成后立即终止,它不会等待所有其他promise完成。与返回一组已解决值(resolvedvalues)的Promise.all()不同,我们只得到一个成功值(假设至少有一个promise被resolved)。当我们只需要一个promise成功而不关心是哪个时,这种方法很有用。此外,与始终返回第一个结果值(已解决/拒绝)的Promise.race()不同,此方法返回第一个成功的值。此方法将忽略所有被拒绝的承诺,直到第一个承诺得到履行。示例constpromise1=newPromise((resolve,reject)=>{setTimeout(reject,100,'promise1rejected');});constpromise2=newPromise((resolve,reject)=>{setTimeout(resolve,400,'promise2resolvedat400ms');});constpromise3=newPromise((resolve,reject)=>{setTimeout(resolve,700,'promise3resolvedat800ms');});(async()=>{try{letvalue=awaitPromise.any([promise1,promise2,promise3]);console.log(value);}catch(error){console.log(error);}})();//Output-"promise2resolvedat400ms"从上面的代码可以看出Promise.any()主要关注解析值。它忽略在100毫秒时拒绝的promise1,并考虑在400毫秒后解决的promise2的值。从最快的服务器检索资源的真实用例假设访问我们网站的用户可能来自世界各地。如果我们的服务器位于一个位置,那么响应时间将根据每个用户的位置而有所不同。但是如果我们有多台服务器,我们可以使用产生最快响应的那台。在这种情况下,可以使用Promise.any()方法从最快的服务器接收响应。我是小智,下次见!作者:MahdhiRezvi译者:FrontendXiaozhi来源:mediumreal-life-examples-9d8d1b9f8ec9本文转载自微信公众号“大招天下”,可通过以下二维码关注。转载本文请联系大千世界公众号。
