微信搜索【伟大的走向世界】,第一时间与大家分享前端行业动态、学习路径等。本文已收录到GitHubhttps://github.com/qq449245884/xiaozhi,里面有完整的测试站点、资料和我的一线厂商访谈系列文章。开篇,async/await不仅仅是Promise之上的语法糖,因为async/await确实提供了实实在在的好处。async/await使异步代码同步,使代码更具表现力和可读性。async/await统一了异步编程体验;并提供更好的错误堆栈跟踪。关于JS中异步编程的一点历史异步编程在JavaScript中很常见。每当我们需要进行网络服务调用、文件访问或数据库操作时,尽管语言是单线程的,异步性是我们防止用户界面阻塞的方式。在ES6之前,回调是猿类处理异步编程的方式。我们可以表达时间依赖性(即异步操作的执行顺序)的唯一方法是将一个回调嵌套在另一个回调中,这会导致所谓的回调地狱。Es6中引入了Promise,它是用于异步操作的一流对象,我们可以轻松地传递、组合、聚合和应用转换。通过then方法链可以清楚地表达时间依赖性。有了Promises这个强大的伙伴,听起来异步编程在JS中是一个解决的问题,对吧?好吧,还没有,因为有时Promises太低级而无用。有时Promises太低级而无用尽管有Promises,但在JS中仍然需要更高级别的语言结构来进行异步编程。让我们看一个例子,假设我们需要一个函数来以特定的时间间隔轮询API。当达到最大重试次数时,它解析为null。这是Promise的解决方案:letcount=0;functionapiCall(){returnnewPromise((resolve)=>//a在第6次重试时被解析为“value”。计数++===5?resolve('value'):resolve(null));}functionsleep(interval){returnnewPromise((resolve)=>setTimeout(resolve,interval));}functionpoll(retry,interval){returnnewPromise((resolve)=>{//为简洁起见跳过错误处理if(retry===0)resolve(null);apiCall().then((val)=>{if(val!==null)resolve(val);else{sleep(interval).then(()=>{resolve(poll(retry-1,interval));});}});});}poll(6,1000).then(console.log);//'value'这个解决方案的直观性和可读性取决于一个人对Promises的熟悉程度,以及Promise.resolve如何“平铺”Promise和递归。对我来说,这不是编写此类函数的最易读的方式。使用async/await我们用async/await语法重写上面的解决方案:asyncfunctionpoll(retry,interval){while(retry>=0){constvalue=awaitapiCall().catch((e)=>{});如果(值!==null)返回值;等待睡眠(间隔);重试-;}returnnull;}我认为大多数人会发现上述解决方案更具可读性,因为我们可以使用所有Normal语言结构,例如循环、用于异步操作的try-catch等。这可能是async/await最大的卖点——允许我们以同步的方式编写异步代码。另一方面,这可能是对async/await最常见的反对意见的来源,稍后会详细介绍。顺便说一下,await甚至具有正确的运算符优先级,所以awaita+awaitb等于(awaita)+(awaitb)而不是await(a+awaitb)。async/await提供同步和异步代码的统一体验async/await的另一个好处是await自动将任何非Promise(非thenables)包装到Promises中。await的语义等同于Promise.resolve,这意味着你可以等待任何东西:functionfetchValue(){return1;}asyncfunctionfn(){constval=awaitfetchValue();控制台日志(val);//1}//上面相当于下面functionfn(){Promise.resolve(fetchValue()).then((val)=>{console.log(val);//1});}如果我们附加then方法到fetchValue返回的数字1上,出现如下错误。functionfetchValue(){return1;}functionfn(){fetchValue().then((val)=>{console.log(val);});}fn();//?未捕获的类型错误:fetchValue(...).then不是一个函数最后,从异步函数返回的任何东西都是一个Promise:Object.prototype.toString.call((asyncfunction(){})());//'[objectPromise]'async/awaitprovidesbettererrorstacktracesV8工程师Mathias写了一篇名为Asynchronousstacktraces:whyawaitbeatsPromise#then()的文章,解释了为什么引擎比async更容易捕捉和存储/await的Promise堆栈跟踪。示例:asyncfunctionfoo(){awaitbar();返回“价值”;}functionbar(){thrownewError('BEEPBEEP');}foo().catch((error)=>console.log(error.stack));//Error:BEEPBEEP//atbar(
