原文链接:http://aisk.me/using-async-await-to-avoid-callback-hell/

JavaScript 中最蛋疼的事情莫过于回调函数嵌套问题。以往在浏览器中,因为与服务器通讯是一种比较昂贵的操作,因此比较复杂的业务逻辑往往都放在服务器端,前端 JavaScript 只需要少数几次 AJAX 请求就可拿到全部数据。

但是到了 webapp 风行的时代,前端业务逻辑越来越复杂,往往几个 AJAX 请求之间互有依赖,有些请求依赖前面请求的数据,有些请求需要并行进行。还有在类似 node.js 的后端 JavaScript 环境中,因为需要进行大量 IO 操作,问题更加明显。这个时候使用回调函数来组织代码往往会导致代码难以阅读。

现在比较流行的解决这个问题的方法是使用 Promise,可以将嵌套的回调函数展平。但是写代码和阅读依然有额外的负担。

另外一个方案是使用 ES6 中新增的 generator,因为 generator 的本质是可以将一个函数执行暂停,并保存上下文,再次调用时恢复当时的状态。co 模块是个不错的封装。但是这样略微有些滥用 generator 特性的感觉。

ES7 中有了更加标准的解决方案,新增了 async/await 两个关键词。async 可以声明一个异步函数,此函数需要返回一个 Promise 对象。await 可以等待一个 Promise 对象 resolve,并拿到结果。

比如下面的例子,以往我们无法在 JavaScript 中使用常见的 sleep 函数,只能使用 setTimeout 来注册一个回调函数,在指定的时间之后再执行。有了 async/await 之后,我们就可以这样实现了:

async function sleep(timeout) {
  return new Promise((resolve, reject) => {
    setTimeout(function() {
      resolve();
    }, timeout);
  });
}

(async function() {
  console.log('Do some thing, ' + new Date());
  await sleep(3000);
  console.log('Do other things, ' + new Date());
})();

执行此段代码,可以在终端中看到结果:

Do some thing, Mon Feb 23 2015 21:52:11 GMT+0800 (CST)
Do other things, Mon Feb 23 2015 21:52:14 GMT+0800 (CST)

另外 async 函数可以正常的返回结果和抛出异常。await 函数调用即可拿到结果,在外面包上 try/catch 就可以捕获异常。下面是一个从豆瓣 API 获取数据的例子:

var fetchDoubanApi = function() {
  return new Promise((resolve, reject) => {
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
      if (xhr.readyState === 4) {
        if (xhr.status >= 200 && xhr.status < 300) {
          var response;
          try {
            response = JSON.parse(xhr.responseText);
          } catch (e) {
            reject(e);
          }
          if (response) {
            resolve(response, xhr.status, xhr);
          }
        } else {
          reject(xhr);
        }
      }
    };
    xhr.open('GET', 'https://api.douban.com/v2/user/aisk', true);
    xhr.setRequestHeader("Content-Type", "text/plain");
    xhr.send(data);
  });
};

(async function() {
  try {
    let result = await fetchDoubanApi();
    console.log(result);
  } catch (e) {
    console.log(e);
  }
})();

ES7 还在草案阶段,那现在想用这个特性怎么办?可以尝试 google 的一个 JavaScript 预编译器 traceur,可以将高版本的 JavaScript 编译为 ES5 代码,已经实验性的支持了 async/await (需要使用 --experimental 来指定开启)。traceur 可以直接在后端使用,也可以在浏览器中使用。另外如果只在 node.js 环境中使用的话,还有一些 polyfill 模块,比如这个

JavaScript ES7 中使用 async/await 解决回调函数嵌套问题的更多相关文章

  1. 理解ES7中的async/await

    理解ES7中的async/await 优势是:就是解决多层异步回调的嵌套 从字面上理解 async/await, async是 "异步"的含义,await可以认为是 async w ...

  2. 不使用回调函数的ajax请求实现(async和await简化回调函数嵌套)

    在常规的服务器端程序设计中, 比如说爬虫程序, 发送http请求的过程会使整个执行过程阻塞,直到http请求响应完成代码才会继续执行, 以php为例子 $url = "http://www. ...

  3. 关于ES7中的async/await在客户端和服务端上的实践

    一.前言 在项目中经常遇到处理异步请求的情况,面对层层的嵌套,回调显示那么苍白无力: async / await是ES7的重要特性之一,也是目前社区里公认的优秀异步解决方案,既然这样就用上吧. 二.配 ...

  4. Promise,async/await解决回调地狱

    先说一下async的用法,它作为一个关键字放到函数前面,用于表示函数是一个异步函数,因为async就是异步的意思, 异步函数也就意味着该函数的执行不会阻塞后面代码的执行. 写一个async 函数 as ...

  5. ES7中的async和await

    ES7中的async和await 在上一章中,使用Promise将原本的回调方式转换为链式操作,这就将一个个异步执行的操作串在一条同步线上了.下一次的操作必须等待当前操作的结束. 使用Promise的 ...

  6. js中的async await

    JavaScript 中的 async/await 是属于比较新的知识,在ES7中被提案在列,然而我们强大的babel粑粑已经对它进行列支持! 如果开发中使用了babel转码,那么就放心大胆的用吧. ...

  7. 【TypeScript】如何在TypeScript中使用async/await,让你的代码更像C#。

    [TypeScript]如何在TypeScript中使用async/await,让你的代码更像C#. async/await 提到这个东西,大家应该都很熟悉.最出名的可能就是C#中的,但也有其它语言也 ...

  8. 在现有代码中通过async/await实现并行

    在现有代码中通过async/await实现并行 一项新技术或者一个新特性,只有你用它解决实际问题后,才能真正体会到它的魅力,真正理解它.也期待大家能够多分享解一些解决实际问题的内容. 在我们遭遇“黑色 ...

  9. 浅谈C#中的 async await 以及对线程相关知识的复习

    C#5.0以后新增了一个语法糖,那就是异步方法async await,之前对线程,进程方面的知识有过较为深入的学习,大概知道这个概念,我的项目中实际用到C#异步编程的场景比较少,就算要用到一般也感觉T ...

随机推荐

  1. C#中listbox中选中多项,并删除

    1.SelectionMode 改成可以多选2.利用KeyDown事件: private void listBox1_KeyDown(object sender, KeyEventArgs e) { ...

  2. ORB:新一代 Linux 应用

    Orbital Apps 给我们带来了一种新的软件包类型 ORB,它具有便携软件.交互式安装向导支持,以及离线使用的能力. 便携软件很方便.主要是因为它们能够无需任何管理员权限直接运行,也能够带着所有 ...

  3. 类的__slots__属性

    为什么有"slots"属性? 默认情况下,python对象队象的每个实例(instance)都会有一个字典来存储该实例的属性,这样做的好处在于运行时期每个对象可以任意设置新的属性. ...

  4. Android&iOS崩溃堆栈上报

    Android&iOS崩溃堆栈上报 原文地址:http://www.cnblogs.com/songcf/p/4885468.html 通过崩溃捕获和收集,可以收集到已发布应用(游戏)的异常, ...

  5. css+div网页设计(一)--基础知识

    css是网页制作不可缺少的部分,我会用三篇博客为大家展示css的基本用法. 关于css+div的整体结构图总结如下: 本篇博客主要介绍css的基础知识. 一.css概念; css(级联样式表):它是一 ...

  6. Mindjet MindManager 2016/2017 折腾记录

    https://community.mindjet.com/mindjet/topics/ensure-2017-64-bit-version-installation Mindmanager sho ...

  7. 使用Word 2013向cnblog发布博文

    Windows Live软件许久不更新,就想用手头的Word 2013作为cnblogs博客的撰写工具.在查看cnblogs关于Windows Live的配置说明时,发现下列有Word 2007的配置 ...

  8. 转:视频压缩的基本概念(x264解压包)

    第1页:前言——视频压缩无处不在H.264 或者说 MPEG-4 AVC 是目前使用最广泛的高清视频编码标准,和上一代 MPEG-2.h.263/MPEG-4 Part4 相比,它的压缩率大为提高,例 ...

  9. 添加iPhone设备的udid之后,重新生成开发证书(Development)

    选择Provisioning profiles-Development-添加 ,如图:

  10. latex之设置字体大小

    \tiny\scriptsize\footnotesize\small\normalsize\large\Large\LARGE\huge\Huge