ES6中Async函数的详细介绍(附示例)

本篇文章给大家带来的内容是关于es6中async函数的详细介绍(附示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

async

ES2017 标准引入了 async 函数,使得异步操作变得更加方便。

在异步处理上,async 函数就是 Generator 函数的语法糖。

举个例子:

// 使用 generatorvar fetch = require('node-fetch');var co = require('co');function* gen() {    var r1 = yield fetch('https://api.github.com/users/github');    var json1 = yield r1.json();    console.log(json1.bio);}co(gen);

登录后复制

当你使用 async 时:

// 使用 asyncvar fetch = require('node-fetch');var fetchData = async function () {    var r1 = await fetch('https://api.github.com/users/github');    var json1 = await r1.json();    console.log(json1.bio);};fetchData();

登录后复制

其实 async 函数的实现原理,就是将 Generator 函数和自动执行器,包装在一个函数里。

async function fn(args) {  // ...}// 等同于function fn(args) {  return spawn(function* () {    // ...  });}

登录后复制

spawn 函数指的是自动执行器,就比如说 co。

再加上 async 函数返回一个 Promise 对象,你也可以理解为 async 函数是基于 Promise 和 Generator 的一层封装。

async 与 Promise

严谨的说,async 是一种语法,Promise 是一个内置对象,两者并不具备可比性,更何况 async 函数也返回一个 Promise 对象……

这里主要是展示一些场景,使用 async 会比使用 Promise 更优雅的处理异步流程。

1. 代码更加简洁

/** * 示例一 */function fetch() {  return (    fetchData()    .then(() => {      return "done"    });  )}async function fetch() {  await fetchData()  return "done"};

登录后复制

/** * 示例二 */function fetch() {  return fetchData()  .then(data => {    if (data.moreData) {        return fetchAnotherData(data)        .then(moreData => {          return moreData        })    } else {      return data    }  });}async function fetch() {  const data = await fetchData()  if (data.moreData) {    const moreData = await fetchAnotherData(data);    return moreData  } else {    return data  }};

登录后复制

/** * 示例三 */function fetch() {  return (    fetchData()    .then(value1 => {      return fetchMoreData(value1)    })    .then(value2 => {      return fetchMoreData2(value2)    })  )}async function fetch() {  const value1 = await fetchData()  const value2 = await fetchMoreData(value1)  return fetchMoreData2(value2)};

登录后复制

2. 错误处理

function fetch() {  try {    fetchData()      .then(result => {        const data = JSON.parse(result)      })      .catch((err) => {        console.log(err)      })  } catch (err) {    console.log(err)  }}

登录后复制

在这段代码中,try/catch 能捕获 fetchData() 中的一些 Promise 构造错误,但是不能捕获 JSON.parse 抛出的异常,如果要处理 JSON.parse 抛出的异常,需要添加 catch 函数重复一遍异常处理的逻辑。

在实际项目中,错误处理逻辑可能会很复杂,这会导致冗余的代码。

async function fetch() {  try {    const data = JSON.parse(await fetchData())  } catch (err) {    console.log(err)  }};

登录后复制

async/await 的出现使得 try/catch 就可以捕获同步和异步的错误。

3. 调试

const fetchData = () => new Promise((resolve) => setTimeout(resolve, 1000, 1))const fetchMoreData = (value) => new Promise((resolve) => setTimeout(resolve, 1000, value + 1))const fetchMoreData2 = (value) => new Promise((resolve) => setTimeout(resolve, 1000, value + 2))function fetch() {  return (    fetchData()    .then((value1) => {      console.log(value1)      return fetchMoreData(value1)    })    .then(value2 => {      return fetchMoreData2(value2)    })  )}const res = fetch();console.log(res);

登录后复制

1047790184-5bcf3f279db90_articlex.gif

因为 then 中的代码是异步执行,所以当你打断点的时候,代码不会顺序执行,尤其当你使用 step over 的时候,then 函数会直接进入下一个 then 函数。

const fetchData = () => new Promise((resolve) => setTimeout(resolve, 1000, 1))const fetchMoreData = () => new Promise((resolve) => setTimeout(resolve, 1000, 2))const fetchMoreData2 = () => new Promise((resolve) => setTimeout(resolve, 1000, 3))async function fetch() {  const value1 = await fetchData()  const value2 = await fetchMoreData(value1)  return fetchMoreData2(value2)};const res = fetch();console.log(res);

登录后复制

3592311766-5bcf3f27d9b1e_articlex.gif

而使用 async 的时候,则可以像调试同步代码一样调试。

async 地狱

async 地狱主要是指开发者贪图语法上的简洁而让原本可以并行执行的内容变成了顺序执行,从而影响了性能,但用地狱形容有点夸张了点……

例子一

举个例子:

(async () => {  const getList = await getList();  const getAnotherList = await getAnotherList();})();

登录后复制

getList() 和 getAnotherList() 其实并没有依赖关系,但是现在的这种写法,虽然简洁,却导致了 getAnotherList() 只能在 getList() 返回后才会执行,从而导致了多一倍的请求时间。

为了解决这个问题,我们可以改成这样:

(async () => {  const listPromise = getList();  const anotherListPromise = getAnotherList();  await listPromise;  await anotherListPromise;})();

登录后复制

也可以使用 Promise.all():

(async () => {  Promise.all([getList(), getAnotherList()]).then(...);})();

登录后复制

例子二

当然上面这个例子比较简单,我们再来扩充一下:

(async () => {  const listPromise = await getList();  const anotherListPromise = await getAnotherList();  // do something  await submit(listData);  await submit(anotherListData);})();

登录后复制

因为 await 的特性,整个例子有明显的先后顺序,然而 getList() 和 getAnotherList() 其实并无依赖,submit(listData) 和 submit(anotherListData) 也没有依赖关系,那么对于这种例子,我们该怎么改写呢?

基本分为三个步骤:

1. 找出依赖关系

在这里,submit(listData) 需要在 getList() 之后,submit(anotherListData) 需要在 anotherListPromise() 之后。

2. 将互相依赖的语句包裹在 async 函数中

async function handleList() {  const listPromise = await getList();  // ...  await submit(listData);}async function handleAnotherList() {  const anotherListPromise = await getAnotherList()  // ...  await submit(anotherListData)}

登录后复制

3.并发执行 async 函数

async function handleList() {  const listPromise = await getList();  // ...  await submit(listData);}async function handleAnotherList() {  const anotherListPromise = await getAnotherList()  // ...  await submit(anotherListData)}// 方法一(async () => {  const handleListPromise = handleList()  const handleAnotherListPromise = handleAnotherList()  await handleListPromise  await handleAnotherListPromise})()// 方法二(async () => {  Promise.all([handleList(), handleAnotherList()]).then()})()

登录后复制

继发与并发

问题:给定一个 URL 数组,如何实现接口的继发和并发?

async 继发实现:

// 继发一async function loadData() {  var res1 = await fetch(url1);  var res2 = await fetch(url2);  var res3 = await fetch(url3);  return "whew all done";}

登录后复制

// 继发二async function loadData(urls) {  for (const url of urls) {    const response = await fetch(url);    console.log(await response.text());  }}

登录后复制

async 并发实现:

// 并发一async function loadData() {  var res = await Promise.all([fetch(url1), fetch(url2), fetch(url3)]);  return "whew all done";}

登录后复制

// 并发二async function loadData(urls) {  // 并发读取 url  const textPromises = urls.map(async url => {    const response = await fetch(url);    return response.text();  });  // 按次序输出  for (const textPromise of textPromises) {    console.log(await textPromise);  }}

登录后复制

async 错误捕获

尽管我们可以使用 try catch 捕获错误,但是当我们需要捕获多个错误并做不同的处理时,很快 try catch 就会导致代码杂乱,就比如:

async function asyncTask(cb) {    try {       const user = await UserModel.findById(1);       if(!user) return cb('No user found');    } catch(e) {        return cb('Unexpected error occurred');    }    try {       const savedTask = await TaskModel({userId: user.id, name: 'Demo Task'});    } catch(e) {        return cb('Error occurred while saving task');    }    if(user.notificationsEnabled) {        try {            await NotificationService.sendNotification(user.id, 'Task Created');        } catch(e) {            return cb('Error while sending notification');        }    }    if(savedTask.assignedUser.id !== user.id) {        try {            await NotificationService.sendNotification(savedTask.assignedUser.id, 'Task was created for you');        } catch(e) {            return cb('Error while sending notification');        }    }    cb(null, savedTask);}

登录后复制

为了简化这种错误的捕获,我们可以给 await 后的 promise 对象添加 catch 函数,为此我们需要写一个 helper:

// to.jsexport default function to(promise) {   return promise.then(data => {      return [null, data];   })   .catch(err => [err]);}

登录后复制

整个错误捕获的代码可以简化为:

import to from './to.js';async function asyncTask() {     let err, user, savedTask;     [err, user] = await to(UserModel.findById(1));     if(!user) throw new CustomerError('No user found');     [err, savedTask] = await to(TaskModel({userId: user.id, name: 'Demo Task'}));     if(err) throw new CustomError('Error occurred while saving task');    if(user.notificationsEnabled) {       const [err] = await to(NotificationService.sendNotification(user.id, 'Task Created'));       if (err) console.error('Just log the error and continue flow');    }}

登录后复制

async 的一些讨论

async 会取代 Generator 吗?

Generator 本来是用作生成器,使用 Generator 处理异步请求只是一个比较 hack 的用法,在异步方面,async 可以取代 Generator,但是 async 和 Generator 两个语法本身是用来解决不同的问题的。

async 会取代 Promise 吗?

async 函数返回一个 Promise 对象

面对复杂的异步流程,Promise 提供的 all 和 race 会更加好用

Promise 本身是一个对象,所以可以在代码中任意传递

async 的支持率还很低,即使有 Babel,编译后也要增加 1000 行左右。

以上就是ES6Async函数的详细介绍(附示例)的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2738270.html

(0)
上一篇 2025年3月8日 01:48:34
下一篇 2025年2月26日 07:05:16

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • javascript数组操作方法总结一览(附示例)

    本篇文章给大家带来的内容是关于javascript数组操作方法总结一览(附示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 ECMAScript为操作已经包含在数组中的项提供了很多方法。这里本人总结一下自己对这些方法的…

    编程技术 2025年3月8日
    200
  • 如何二次封装axios并根据参数来实现多个请求多次拦截(代码)

    本篇文章给大家带来的内容是关于如何二次封装axios并根据参数来实现多个请求多次拦截(代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 1、新建 axiosTool.js 文件,设置请求拦截和处理的逻辑 import …

    编程技术 2025年3月8日
    200
  • 如何用HTML+CSS+JavaScript制作简易计算器

    javascript是前端开发中必不可少的一部分,因为页面功能的实现离不开js,作为一个前端开发人员,你会用javascript制作一个简易计算器吗?这篇文章就给大家讲讲如何用html、css、javascript制作一个简易计算器,并且能…

    2025年3月8日
    200
  • <script>标签中六个属性的介绍

    本篇文章给大家带来的内容是关于标签中六个属性的介绍,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 属性一:async 可选async是html5新加的一个属性,官方一点说,表示应该立即下载脚本,但是不妨碍页面其他操作,通俗…

    编程技术 2025年3月8日
    200
  • js中根据json生成html表格的方法介绍(代码)

    本篇文章给大家带来的内容是关于js中根据json生成html表格的方法介绍(代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 之前公司有一个需求是:通过js来生成html。而且大部分都是生成表格,直接通过字符串拼接的话…

    编程技术 2025年3月8日
    200
  • ECMAScript6中Promise是什么?有什么用?(附示例)

    本篇文章给大家带来的内容是关于ecmascript6中promise是什么?有什么用?(附示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 刚学习完,有点粗略印象。整理记录一下以便后续学习补充,加深理解。 Promis…

    编程技术 2025年3月8日
    200
  • JavaScript中按值传递的详细介绍

    本篇文章给大家带来的内容是关于JavaScript中按值传递的详细介绍,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 概述 参数的传递分为按值传递和按引用传递,而 javascript 中参数的传递只有按值传递。 ECMA…

    2025年3月8日
    200
  • Vue中使用axios请求拦截的方法介绍

    本篇文章给大家带来的内容是关于vue中使用axios请求拦截的方法介绍,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 一、前言 axios的基础使用就不过多的讲解啦,如何使用可以看axios文档使用说明·Axios中文说明…

    2025年3月8日
    200
  • vue修饰符详细总结(附示例)

    本篇文章给大家带来的内容是关于vue修饰符详细总结(附示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 为了方便大家写代码,vue.js给大家提供了很多方便的修饰符,比如我们经常用到的取消冒泡,阻止默认事件等等~ 目录…

    2025年3月8日 编程技术
    200
  • 带你详细实现vue双向绑定

    本篇文章给大家带来的内容是关于带你详细实现vue双向绑定,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 当今前端天下以 Angular、React、vue 三足鼎立的局面,你不选择一个阵营基本上无法立足于前端,甚至是两个或…

    2025年3月8日 编程技术
    200

发表回复

登录后才能评论