Async/Await替换Promise的6个来由

译者按: Node.js的异步编程体式格局有效进步了运用机能;然则回调地狱却让人望而却步,Promise让我们离别回调函数,写出更文雅的异步代码;在实践过程当中,却发明Promise并不圆满;技术进步是无止境的,这时候,我们有了Async/Await。

《Async/Await替换Promise的6个来由》

为了保证可读性,本文采纳意译而非直译。

Node.js 7.6已支撑async/await了,假如你还没有试过,这篇博客将通知你为何要用它。

Async/Await简介

关于从未听说过async/await的朋侪,下面是简介:

  • async/await是写异步代码的新体式格局,之前的要领有回调函数Promise
  • async/await是基于Promise完成的,它不能用于一般的回调函数。
  • async/await与Promise一样,黑白壅塞的。
  • async/await使得异步代码看起来像同步代码,这正是它的魔力地点。

Async/Await语法

示例中,getJSON函数返回一个promise,这个promise胜利resolve时会返回一个json对象。我们只是挪用这个函数,打印返回的JSON对象,然后返回”done”。

运用Promise是如许的:

const makeRequest = () =>
  getJSON()
    .then(data => {
      console.log(data)
      return "done"
    })

makeRequest()

运用Async/Await是如许的:

const makeRequest = async () => {
  console.log(await getJSON())
  return "done"
}

makeRequest()

它们有一些纤细差别:

  • 函数前面多了一个async关键字。await关键字只能用在async定义的函数内。async函数会隐式地返回一个promise,该promise的reosolve值就是函数return的值。(示例中reosolve值就是字符串”done”)
  • 第1点暗示我们不能在最外层代码中运用await,由于不在async函数内。
// 不能在最外层代码中运用await
await makeRequest()

// 这是会出事变的 
makeRequest().then((result) => {
  // 代码
})

await getJSON()示意console.log会比及getJSON的promise胜利reosolve以后再实行。

为何Async/Await更好?

1. 简约

由示例可知,运用Async/Await显著勤俭了不少代码。我们不须要写.then,不须要写匿名函数处置惩罚Promise的resolve值,也不须要定义过剩的data变量,还防止了嵌套代码。这些小的长处会敏捷累计起来,这在以后的代码示例中会越发显著。

2. 毛病处置惩罚

Async/Await让try/catch可以同时处置惩罚同步和异步毛病。鄙人面的promise示例中,try/catch不能处置惩罚JSON.parse的毛病,由于它在Promise中。我们须要运用.catch,如许毛病处置惩罚代码非常冗余。而且,在我们的现实临盆代码会越发庞杂。

const makeRequest = () => {
  try {
    getJSON()
      .then(result => {
        // JSON.parse能够会失足
        const data = JSON.parse(result)
        console.log(data)
      })
      // 作废解释,处置惩罚异步代码的毛病
      // .catch((err) => {
      //   console.log(err)
      // })
  } catch (err) {
    console.log(err)
  }
}

运用async/await的话,catch能处置惩罚JSON.parse毛病:

const makeRequest = async () => {
  try {
    // this parse may fail
    const data = JSON.parse(await getJSON())
    console.log(data)
  } catch (err) {
    console.log(err)
  }
}

3. 前提语句

下面示例中,须要猎取数据,然后依据返回数据决定是直接返回,照样继承猎取更多的数据。

const makeRequest = () => {
  return getJSON()
    .then(data => {
      if (data.needsAnotherRequest) {
        return makeAnotherRequest(data)
          .then(moreData => {
            console.log(moreData)
            return moreData
          })
      } else {
        console.log(data)
        return data
      }
    })
}

这些代码看着就头痛。嵌套(6层),括号,return语句很轻易让人觉得渺茫,而它们只是须要将终究效果通报到最外层的Promise。

上面的代码运用async/await编写可以大大地进步可读性:

const makeRequest = async () => {
  const data = await getJSON()
  if (data.needsAnotherRequest) {
    const moreData = await makeAnotherRequest(data);
    console.log(moreData)
    return moreData
  } else {
    console.log(data)
    return data    
  }
}

4. 中心值

你极能够遇到过如许的场景,挪用promise1,运用promise1返回的效果去挪用promise2,然后运用二者的效果去挪用promise3。你的代码极多是如许的:

const makeRequest = () => {
  return promise1()
    .then(value1 => {
      return promise2(value1)
        .then(value2 => {        
          return promise3(value1, value2)
        })
    })
}

假如promise3不须要value1,可以很简朴地将promise嵌套摊平。假如你忍受不了嵌套,你可以将value 1 & 2 放进Promise.all来防止深层嵌套:

const makeRequest = () => {
  return promise1()
    .then(value1 => {
      return Promise.all([value1, promise2(value1)])
    })
    .then(([value1, value2]) => {      
      return promise3(value1, value2)
    })
}

这类要领为了可读性捐躯了语义。除了防止嵌套,并没有其他来由将value1和value2放在一个数组中。

运用async/await的话,代码会变得非常简朴和直观。

const makeRequest = async () => {
  const value1 = await promise1()
  const value2 = await promise2(value1)
  return promise3(value1, value2)
}

5. 毛病栈

下面示例中挪用了多个Promise,假定Promise链中某个处所抛出了一个毛病:

const makeRequest = () => {
  return callAPromise()
    .then(() => callAPromise())
    .then(() => callAPromise())
    .then(() => callAPromise())
    .then(() => callAPromise())
    .then(() => {
      throw new Error("oops");
    })
}

makeRequest()
  .catch(err => {
    console.log(err);
    // output
    // Error: oops at callAPromise.then.then.then.then.then (index.js:8:13)
  })

Promise链中返回的毛病栈没有给出毛病发作位置的线索。更蹩脚的是,它会误导我们;毛病栈中唯一的函数名为callAPromise,然则它和毛病没有关系。(文件名和行号照样有效的)。

然则,async/await中的毛病栈会指向毛病地点的函数:

const makeRequest = async () => {
  await callAPromise()
  await callAPromise()
  await callAPromise()
  await callAPromise()
  await callAPromise()
  throw new Error("oops");
}

makeRequest()
  .catch(err => {
    console.log(err);
    // output
    // Error: oops at makeRequest (index.js:7:9)
  })

在开辟环境中,这一点上风并不大。然则,当你剖析临盆环境的毛病日记时,它将非常有效。这时候,晓得毛病发作在makeRequest比晓得毛病发作在then链中要好。

6. 调试

末了一点,也黑白常重要的一点在于,async/await可以使得代码调试更简朴。2个来由使得调试Promise变得非常痛楚:

  • 不能在返回表达式的箭头函数中设置断点

《Async/Await替换Promise的6个来由》

  • 假如你在.then代码块中设置断点,运用Step Over快捷键,调试器不会跳到下一个.then,由于它只会跳过异步代码。

运用await/async时,你不再须要那么多箭头函数,如许你就可以像调试同步代码一样跳过await语句。

《Async/Await替换Promise的6个来由》

结论

Async/Await是近年来JavaScript增加的最革命性的特征之一。它会让你发明Promise的语法有多蹩脚,而且供应了一个直观的替换要领。

忧愁

关于Async/Await,或许你有一些合理的疑心:

  • 它使得异步代码不再显著: 我们已习气了用回调函数或许.then来辨认异步代码,我们能够须要花数个礼拜去习气新的标志。然则,C#具有这个特征已很多年了,熟习它的朋侪应当晓得临时的轻微不方便是值得的。
  • Node 7不是LTS(历久支撑版本): 然则,Node 8下个月就会宣布,将代码迁移到新版本会非常简朴。(Fundebug注:Node 8是LTS,已于2017年10月正式宣布。)

关于Fundebug

Fundebug专注于JavaScript、微信小顺序、微信小游戏、支付宝小顺序、React Native、Node.js和Java线上运用及时BUG监控。 自从2016年双十一正式上线,Fundebug累计处置惩罚了10亿+毛病事宜,付费客户有Google、360、金山软件、百姓网等浩瀚品牌企业。迎接人人免费试用

《Async/Await替换Promise的6个来由》

版权声明

转载时请说明作者Fundebug以及本文地点:
https://blog.fundebug.com/2017/04/04/nodejs-async-await/

    原文作者:Fundebug
    原文地址: https://segmentfault.com/a/1190000008946428
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞