异步的 JavaScript 从未如何简单! 过去段时间, 我们使用回调. 然后, 我们使用 promises. 现在, 我们有了异步功能函数.
异步函数能够使得 (我们) 编写异步 JavaScript 更加容易, 但是, 它自带一套陷阱, 对初学者很不友好.
在这个由两部分组成的文章中, 我想分享下你需要了解的有关异步函数的内容.[PS: 另一部分暂不打算翻译]
异步功能
异步功能函数包含 async 关键词. 你可以在正常的函数声明中使用它:
- async function functionName (arguments) {
- // Do something asynchronous
- }
你也可以使用箭头函数.
- const functionName = async (arguments) => {
- // Do something asynchronous
- }
异步函数总是返回 promises
(异步函数)它不管你返回什么. 其返回值都是 promise.
- const getOne = async _ => {
- return 1
- }
- const promise = getOne()
- console.log(promise) // Promise
笔记: 在接着往前读之前, 你应该知道什么是 JavaScript Promises 知识点, 以及如何使用它们. 否则, 它会开始变得混乱. 这篇文章会帮助你熟悉 JavaScript Promise.
await 关键字
当你调用 promise 时, 你会在 then 中处理下一步, 如下:
- const getOne = async _ => {
- return 1
- }
- getOne()
- .then(value => {
- console.log(value) // 1
- })
await 关键字允许你等待 promise 去解析. 一旦解析完 promise, 它就会返回参数传递给 then 调用.
- const test = async _ => {
- const one = await getOne()
- console.log(one) // 1
- }
- test()
返回 await
在返回承诺 (promise) 之前没有必要等待(await). 你可以直接退回承诺.
如果你 return await 些内容, 则你首先是解决了原先 promise. 然后, 你从已经解析的内容 (resolved value) 创建新的 promise.return await 真的没做什么有效的东西. 无需额外的步骤.
- // Don't need to do this
- const test = async _ => {
- return await getOne()
- }
- test()
- .then(value => {
- console.log(value) // 1
- })
- // Do this instead
- const test = async _ => {
- return getOne()
- }
- test()
- .then(value => {
- console.log(value) // 1
- })
注意: 如果你不需要 await, 则不需要使用异步功能(async function). 上面的例子可以改写如下:
- // Do this instead
- const test = _ => {
- return getOne()
- }
- test()
- .then(value => {
- console.log(value) // 1
- })
处理错误
如果一个 promise 出错了, 你可以使用 catch 调用来处理它, 如下所示:
- const getOne = async (success = true) => {
- if (success) return 1
- throw new Error('Failure!')
- }
- getOne(false)
- .catch(error => console.log(error)) // Failure!
如果你想在一个异步函数中处理错误, 你需要调用 try/catch.
- const test = async _ => {
- try {
- const one = await getOne(false)
- } catch (error) {
- console.log(error) // Failure!
- }
- }
- test()
如果你有多个 await 关键字, 错误处理可能变得很难看...
- const test = async _ => {
- try {
- const one = await getOne(false)
- } catch (error) {
- console.log(error) // Failure!
- }
- try {
- const two = await getTwo(false)
- } catch (error) {
- console.log(error) // Failure!
- }
- try {
- const three = await getThree(false)
- } catch (error) {
- console.log(error) // Failure!
- }
- }
- test()
还有更好的方法.
我们知道异步函数总是返回一个 promise. 当我们调用 promise 时, 我们可以在 catch 调用中处理错误. 这意味着我们可以通过添加. catch 来处理异步函数中的任何错误.
- const test = async _ => {
- const one = await getOne(false)
- const two = await getTwo(false)
- const three = await getThree(false)
- }
- test()
- .catch(error => console.log(error)))
注意: Promise 的 catch 方法只允许你捕获一个错误.
多个 awaits
await 阻止 JavaScript 执行下一行代码, 直到 promise 解析为止. 这可能会导致代码执行速度减慢的意外效果.
为了实际演示这点, 我们需要在解析 promise 之前创建一个延迟. 我们可以使用 sleep 功能来创建延迟.
- const sleep = ms => {
- return new Promise(resolve => setTimeout(resolve, ms))
- }
ms 是解析前等待的毫秒数. 如果你传入 1000 到 sleep 函数, JavaScript 将等待一秒才能解析 promise.
- // Using Sleep
- console.log('Now')
- sleep(1000)
- .then(v => {
- console.log('After one second')
- })
sleep
假设 getOne 需要一秒来解析. 为了创建这个延迟, 我们将 1000(一秒)传入到 sleep. 一秒过后, sleeppromise 解析后, 我们返回值 1.
- const getOne = _ => {
- return sleep(1000).then(v => 1)
- }
如果你使用 await getOne(), 你会发现在 getOne 解析之前需要一秒钟.
- const test = async _ => {
- console.log('Now')
- const one = await getOne()
- console.log(one)
- }
- test()
block-1
现在, 假设你需要处理三个 promises. 每个 promise 都有一秒钟的延迟.
- const getOne = _ => {
- return sleep(1000).then(v => 1)
- }
- const getTwo = _ => {
- return sleep(1000).then(v => 2)
- }
- const getThree = _ => {
- return sleep(1000).then(v => 3)
- }
如果你连续 await 这三个 promises, 你将要等待三秒才能解析完所有 promises. 这并不好, 因为我们强迫 JavaScript 在做我们需要做的事情之前等待了两秒钟.
- const test = async _ => {
- const one = await getOne()
- console.log(one)
- const two = await getTwo()
- console.log(two)
- const three = await getThree()
- console.log(three)
- console.log('Done')
- }
- test()
block-2
如果 getOne,getTwo 和 getThree 可以同时获取, 你将节省两秒钟. 你可以使用 Promise.all 同时获取这三个 promises.
有三个步骤:
创建三个 promises
将三个 promises 添加到一个数组中
使用 Promise.all 来 awaitpromises 数组
如下所示:
- const test = async _ => {
- const promises = [getOne(), getTwo(), getThree()]
- console.log('Now')
- const [one, two, three] = await Promise.all(promises)
- console.log(one)
- console.log(two)
- console.log(three)
- console.log('Done')
- }
- test()
block-3
这就是你需要了解的基本异步功能函数! 我希望这篇文章为你扫除了些障碍.
笔记: 这篇文章是 Learn JavaScript 的修改摘录. 如果你发现本文有用, 你可能需要去查看它.
后话
来源: http://www.jianshu.com/p/bd73d8d4426e