专栏名称: 前端大全
分享 Web 前端相关的技术文章、工具资源、精选课程、热点资讯
目录
相关文章推荐
51好读  ›  专栏  ›  前端大全

ES2017 异步函数现已正式可用

前端大全  · 公众号  · 前端  · 2017-08-23 20:30

正文

请到「今天看啥」查看全文


(点击 上方公众号 ,可快速关注)


英文:ERIC WINDMILL  译文:葡萄城控件

www.cnblogs.com/powertoolsteam/p/es2017.html

如有好文章投稿,请点击 → 这里了解详情


ES2017标准已于2017年6月份正式定稿了,并广泛支持最新的特性:异步函数。如果你曾经被异步 JavaScript 的逻辑困扰,这么新函数正是为你设计的。


异步函数或多或少会让你编写一些顺序的 JavaScript 代码,但是却不需要在 callbacks、generators 或 promise 中包含你的逻辑。


如下代码:


function logger () {

let data = fetch ( 'http://sampleapi.com/posts' )

console . log ( data )

}

logger ()


这段代码并未实现你的预期。如果你是在JS中编写的,那么你可能会知道为什么。


下面这段代码,却实现了你的预期。


async function logger () {

let data = await fetch ( 'http:sampleapi.com/posts' )

console . log ( data )

}

logger ()


这段代码起作用了,从直观上看,仅仅只是多了 async 和 await 两个词。


ES6 标准之前的 JavaScript 异步函数


在深入学习 async 和 await 之前,我们需要先理解 Promise。为了领会 Promise,我们需要回到普通回调函数中进一步学习。


Promise 是在 ES6 中引入的,并促使在编写 JavaScript 的异步代码方面,实现了巨大的提升。从此编写回调函数不再那么痛苦。


回调是一个函数,可以将结果传递给函数并在该函数内进行调用,以便作为事件的响应。同时,这也是JS的基础。


function readFile ( 'file.txt' , ( data ) => {

// This is inside the callback function

console . log ( data )

}


这个函数只是简单的向文件中记录数据,在文件完成之前进行读取是不可能的。这个过程似乎很简单,但是如果想要按顺序读取并记录五个不同的文件,需要怎么实现呢?


没有 Promise 的时候,为了按顺序执行任务,就需要通过嵌套回调来实现,就像下面的代码:


// This is officially callback hell

function combineFiles ( file1 , file2 , file3 , printFileCallBack ) {

let newFileText = ''

readFile ( string1 , ( text ) => {

newFileText += text

readFile ( string2 , ( text ) => {

newFileText += text

readFile ( string3 , ( text ) => {

newFileText += text

printFileCallBack ( newFileText )

}

}

}

}


这就很难推断函数下面会发生什么,同时也很难处理各种场景下发生的错误,比如其中某个文件不存在的情况。


Promise 改善了这种情况


这正是 Promise 的优势所在,Promise 是对还未产生的数据的一种推理。Kyle Simpson 将 Promise 解释为:就像在快餐店里点餐一样。


  • 点餐

  • 为所点的午餐付费,并拿到排队单号

  • 等待午餐

  • 当你的午餐准备好了,会叫你的单号提醒你取餐

  • 收到午餐


正如上面的这种场景,当你等餐时,你是无法吃到午餐的,但是你可以提前为吃午餐做好准备。你可以进行其它事情,此时你知道午餐就要来了,虽然此刻你还无法享用它,但是这个午餐已经“promise”给你了。这就是所谓的 promise,表示一个最终会存在的数据的对象。


readFile ( file1 )

. then (( file1 - data ) => { /* do something */ })

. then (( previous - promise - data ) => { /* do the next thing */ })

. catch ( /* handle errors */ )


上面是 Promise 语法。它主要的优点就是可以将队列事件以一种直观的方式链接在一起。虽然这个示例清晰易懂,但是还是用到了回调。Promise 只是让回调显得比较简单和更加直观。


最佳方式:async / await


若干年前,async 函数纳入了 JavaScript 生态系统。就在上个月,async 函数成为了 JavaScript 语言的官方特性,并得到了广泛支持。


async 和 await 是建立在 Promise 和 generator上。本质上,允许我们使用 await 这个关键词在任何函数中的任何我们想要的地方进行暂停。


async function logger () {

// pause until fetch returns

let data = await fetch ( 'http://sampleapi.com/posts' )

console . log ( data )

}


上面这段代码运行之后,得到了想要的结果。代码从 API 调用中记录了数据。


这种方式的好处就是非常直观。编写代码的方式就是大脑思考的方式,告诉脚本在需要的地方暂停。


另一个好处是,当我们不能使用 promise 时,还可以使用 try 和 catch:


async function logger () {

try {

let user_id = await fetch ( '/api/users/username' )

let posts = await fetch ( '/api/`${user_id}`' )

let object = JSON . parse ( user . posts . toString ())

console . log ( posts )

} catch ( error ) {

console . error ( 'Error:' , error )

}

}


上面是一个刻意写错的示例,为了证明了一点:在运行过程中,catch 可以捕获任何步骤中发生的错误。至少有三个地方,try 可能会失败,这是在异步代码中的一种最干净的方式来处理错误。


我们还可以使用带有循环和条件的 async 函数:


async function count () {

let counter = 1

for ( let i = 0 ; i ) {

counter += 1

console . log ( counter )

await sleep ( 1000 )

}

}


这是一个很简答的例子,如果运行这段程序,将会看到代码在 sleep 调用时暂停,下一个循环迭代将会在1秒后启动。


要点和细节


相信我们已经感受到了 asyns 和 await 的美妙之处,接下来让我们深入了解一下细节:


  • async 和 await 建立在 Promise 之上。使用 async,总是会返回一个 Promise。请记住这一点,因为这也是容易犯错的地方。

  • 当执行到 await 时,程序会暂停当前函数,而不是所有代码

  • async 和 await 是非阻塞的

  • 依旧可以使用 Promise helpers,例如 Promise.all( )


正如之前的示例:


async function logPosts () {

try {

let user_id = await fetch ( '/api/users/username' )

let post_ids = await fetch ( '/api/posts/ ${user_id}' )

let promises = post_ids . map ( post_id => {

return fetch ( '/api/posts/${post_id}' )

}

let posts = await Promise . all ( promises )

console . log ( posts )

} catch ( error ) {

console . error ( 'Error:' , error )

}

}


  • await 只能用于声明为 async 的函数中

  • 因此,不能在全局范围内使用 await


如下代码:


// throws an error

function logger ( callBack ) {

console . log ( await callBack )

}

// works!

async function logger () {

console . log ( await callBack )

}


现已正式可用


到2017年6月,几乎所有浏览器都可以使用 async 和 await。为了确保你的代码随时可用,则需要使用 Babel 将你的 JavaScript 代码编译为旧浏览器也支持的语法。


如果对更多ES2017内容感兴趣,请访问ES2017特性的完整列表(http://2ality.com/2016/02/ecmascript-2017.html)。



觉得本文对你有帮助?请分享给更多人

关注「前端大全」,提升前端技能







请到「今天看啥」查看全文


推荐文章
化妆师MK-雷韵祺  ·  长相一般的女生,怎么迅速提升气质
7 年前
中国生物产业信息平台  ·  干细胞领域为何“假”报频传?
7 年前
書衣偵探華斯比  ·  我永远是一名悬疑小说读者
7 年前