├── .gitignore ├── README.png ├── 07-use-await-with-any-thenable.js ├── package.json ├── .editorconfig ├── 01-first-async-await-function.js ├── 02-use-async-function-as-promise.js ├── 04-handling-errors-for-async.js ├── 06-await-multiple-promise-with-all.js ├── 03-convert-any-function-into-async.js ├── 08-await-in-loops.js ├── 05-await-multiple-promise-seq-or-concurrently.js ├── yarn.lock └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /README.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangshijun/course-javascript-async-await/HEAD/README.png -------------------------------------------------------------------------------- /07-use-await-with-any-thenable.js: -------------------------------------------------------------------------------- 1 | const bluebird = require('bluebird'); 2 | 3 | async function main() { 4 | console.log('waiting...'); 5 | await bluebird.delay(2000); 6 | console.log('done!'); 7 | } 8 | 9 | main(); 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "201709-javascript-async-await", 3 | "version": "1.0.0", 4 | "description": "asynchronous javascript with async/await", 5 | "main": "index.js", 6 | "author": "wangshijun2010 ", 7 | "license": "MIT", 8 | "dependencies": { 9 | "bluebird": "^3.5.0", 10 | "node-fetch": "^1.7.2" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs 2 | # editorconfig.org 3 | root = true 4 | 5 | [*] 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = false 9 | insert_final_newline = true 10 | indent_style = space 11 | indent_size = 2 12 | 13 | [{*.yml,*.json}] 14 | indent_style = space 15 | indent_size = 2 16 | -------------------------------------------------------------------------------- /01-first-async-await-function.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch'); 2 | 3 | async function getZhihuColumn(id) { 4 | const url = `https://zhuanlan.zhihu.com/api/columns/${id}`; 5 | const response = await fetch(url); 6 | const column = await response.json(); 7 | console.log(`NAME: ${column.name}`); 8 | console.log(`INTRO: ${column.intro}`); 9 | } 10 | 11 | getZhihuColumn('feweekly'); 12 | -------------------------------------------------------------------------------- /02-use-async-function-as-promise.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch'); 2 | 3 | async function getZhihuColumn(id) { 4 | const url = `https://zhuanlan.zhihu.com/api/columns/${id}`; 5 | const response = await fetch(url); 6 | return await response.json(); 7 | } 8 | 9 | getZhihuColumn('feweekly') 10 | .then(column => { 11 | console.log(`NAME: ${column.name}`); 12 | console.log(`INTRO: ${column.intro}`); 13 | }); 14 | -------------------------------------------------------------------------------- /04-handling-errors-for-async.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch'); 2 | 3 | async function getZhihuColumn(id) { 4 | const url = `https://zhuanlan.zhihu.com/api/columns/${id}`; 5 | const response = await fetch(url); 6 | if (response.status !== 200) { 7 | throw new Error(response.statusText); 8 | } 9 | return await response.json(); 10 | } 11 | 12 | const showColumnInfo = async (id) => { 13 | try { 14 | const column = await getZhihuColumn(id); 15 | console.log(`NAME: ${column.name}`); 16 | console.log(`INTRO: ${column.intro}`); 17 | } catch (err) { 18 | console.error(err); 19 | } 20 | }; 21 | 22 | showColumnInfo('feweekly123'); 23 | -------------------------------------------------------------------------------- /06-await-multiple-promise-with-all.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch'); 2 | 3 | async function getZhihuColumn(id) { 4 | const url = `https://zhuanlan.zhihu.com/api/columns/${id}`; 5 | const response = await fetch(url); 6 | return await response.json(); 7 | } 8 | 9 | const showColumnInfo = async () => { 10 | const [feweekly, toolingtips] = await Promise.all([ 11 | getZhihuColumn('feweekly'), 12 | getZhihuColumn('toolingtips'), 13 | ]); 14 | 15 | console.log(`NAME: ${feweekly.name}`); 16 | console.log(`INTRO: ${feweekly.intro}`); 17 | 18 | console.log(`NAME: ${toolingtips.name}`); 19 | console.log(`INTRO: ${toolingtips.intro}`); 20 | }; 21 | 22 | showColumnInfo(); 23 | -------------------------------------------------------------------------------- /03-convert-any-function-into-async.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch'); 2 | 3 | const getZhihuColumn = async (id) => { 4 | const url = `https://zhuanlan.zhihu.com/api/columns/${id}`; 5 | const response = await fetch(url); 6 | return await response.json(); 7 | }; 8 | 9 | class APIClient { 10 | async getColumn(id) { 11 | const url = `https://zhuanlan.zhihu.com/api/columns/${id}`; 12 | const response = await fetch(url); 13 | return await response.json(); 14 | } 15 | } 16 | 17 | (async () => { 18 | const client = new APIClient(); 19 | const column = await client.getColumn('feweekly'); 20 | // const column = await getZhihuColumn('feweekly'); 21 | console.log(`NAME: ${column.name}`); 22 | console.log(`INTRO: ${column.intro}`); 23 | })(); 24 | 25 | -------------------------------------------------------------------------------- /08-await-in-loops.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch'); 2 | const bluebird = require('bluebird'); 3 | 4 | async function getZhihuColumn(id) { 5 | await bluebird.delay(1000); 6 | const url = `https://zhuanlan.zhihu.com/api/columns/${id}`; 7 | const response = await fetch(url); 8 | return await response.json(); 9 | } 10 | 11 | const showColumnInfo = async () => { 12 | console.time('showColumnInfo'); 13 | 14 | const names = ['feweekly', 'toolingtips']; 15 | const promises = names.map(x => getZhihuColumn(x)); 16 | for (const promise of promises) { 17 | const column = await promise; 18 | console.log(`Name: ${column.name}`); 19 | console.log(`Intro: ${column.intro}`); 20 | } 21 | 22 | console.timeEnd('showColumnInfo'); 23 | }; 24 | 25 | showColumnInfo(); 26 | -------------------------------------------------------------------------------- /05-await-multiple-promise-seq-or-concurrently.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch'); 2 | 3 | const sleep = (timeout = 2000) => new Promise(resolve => { 4 | setTimeout(resolve, timeout); 5 | }); 6 | 7 | async function getZhihuColumn(id) { 8 | await sleep(2000); 9 | const url = `https://zhuanlan.zhihu.com/api/columns/${id}`; 10 | const response = await fetch(url); 11 | return await response.json(); 12 | } 13 | 14 | const showColumnInfo = async () => { 15 | console.time('showColumnInfo'); 16 | const feweekly = await getZhihuColumn('feweekly'); 17 | const toolingtips = await getZhihuColumn('toolingtips'); 18 | 19 | console.log(`NAME: ${feweekly.name}`); 20 | console.log(`INTRO: ${feweekly.intro}`); 21 | 22 | console.log(`NAME: ${toolingtips.name}`); 23 | console.log(`INTRO: ${toolingtips.intro}`); 24 | console.timeEnd('showColumnInfo'); 25 | }; 26 | 27 | showColumnInfo(); 28 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | bluebird@^3.5.0: 6 | version "3.5.0" 7 | resolved "http://registry.npm.taobao.org/bluebird/download/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" 8 | 9 | encoding@^0.1.11: 10 | version "0.1.12" 11 | resolved "http://registry.npm.taobao.org/encoding/download/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" 12 | dependencies: 13 | iconv-lite "~0.4.13" 14 | 15 | iconv-lite@~0.4.13: 16 | version "0.4.18" 17 | resolved "http://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.4.18.tgz#23d8656b16aae6742ac29732ea8f0336a4789cf2" 18 | 19 | is-stream@^1.0.1: 20 | version "1.1.0" 21 | resolved "http://registry.npm.taobao.org/is-stream/download/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" 22 | 23 | node-fetch@^1.7.2: 24 | version "1.7.2" 25 | resolved "http://registry.npm.taobao.org/node-fetch/download/node-fetch-1.7.2.tgz#c54e9aac57e432875233525f3c891c4159ffefd7" 26 | dependencies: 27 | encoding "^0.1.11" 28 | is-stream "^1.0.1" 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 玩转异步 JS :async/await 简明教程 2 | 3 | ## 课程介绍 4 | 5 | 在软件开发领域,简洁的代码 => 容易阅读的代码 => 容易维护的代码,而 ES2017 中的 async/await 特性能让我们编写出相比回调地狱和 Promise 链式调用更直观、更容易理解的代码,await 关键字接收一个 Promise,等待代码执行,直到 Promise 状态变为 resolved 或者 rejected,这种特性能让我们的异步代码阅读起来更像是同步代码。 6 | 7 | 本课程将会从编写简单的 async/await 函数开始,用实例带领大家探索 async/await 实战的方方面面,比如如何结合 Promise 和 await 关键字?如何定义不同类型的 async 函数?如何安全的使用 async/await,即处理错误?如何让多个 await 串行或并行?如何在循环中正确使用 await? 8 | 9 | ## 适用人群 10 | 11 | * [required] 具备 JS 基础知识,知道如何运行 Node.js 脚本; 12 | * [required] 知道 Callback、Promise 等异步处理概念; 13 | * [optional] 期望学习新的异步特性,编写更简洁易懂易维护的代码; 14 | * [optional] 期望不断打磨自己的 JS 技能,让自己变得更值钱; 15 | 16 | ## 内容目录 17 | 18 | ### 1. 编写第一个 async/await 函数 19 | 20 | 手把手教你把发起 HTTP 请求并解析响应的代码改写成 async/await 风格,让你学会 async/await 的基本语法。 21 | 22 | ### 2. 将 async 函数用在 Promise 链中 23 | 24 | 带你探索如何在 Promise 链中像使用其他 Promise 一样无缝使用 async 函数。 25 | 26 | ### 3. 把任意类型的函数转成 async 风格 27 | 28 | 实例演示如何将任意函数写成 async 风格,包括函数声明、函数表达式、箭头函数、类方法、对象方法等。 29 | 30 | ### 4. 处理 async 函数中的错误 31 | 32 | 不同于 Promise 中的 .catch() 错误处理机制,在 async 函数中,我们需要使用 try/catch 结构来恰当的处理错误。 33 | 34 | ### 5. 正确处理多个 await 操作的并行串行 35 | 36 | 学会通过移动 await 关键词的位置实现多个 await 操作串行或者并行,并且用数据证明让多个异步操作并行的性能优势。 37 | 38 | ### 6. 使用 Promise.all() 让多个 await 操作并行 39 | 40 | 学会使用 ES2015 中的解构和 Promise.all() 实现多个异步操作的并行,非常适合需要同时发起多个请求的情形,代码可读性不打折扣。 41 | 42 | ### 7. 结合 await 和任意兼容 .then() 的代码 43 | 44 | await 操作符并不仅仅局限于 ES2015 的 Promise,可以和任意兼容 .then() 方法的代码使用,通过实例学会如何与流行的 Promise 库结合使用。 45 | 46 | ### 8. 在 for 循环中正确的使用 await 47 | 48 | 理解 for 循环中 await 不同写法带来的性能影响,以及改进的方法。 49 | 50 | ## 源码链接 51 | 52 | 代码仓库:[wangshijun/course-javascript-async-await](https://github.com/wangshijun/course-javascript-async-await) 53 | 54 | 运行方法(请确保系统中安装了 [Node.js](https://nodejs.org/en/)): 55 | 56 | ```shell 57 | git clone https://github.com/wangshijun/course-javascript-async-await.git 58 | cd course-javascript-async-await 59 | node xxx.js 60 | ``` 61 | 62 | 上面的 xxx.js 对应每节课程的源码,列表如下: 63 | 64 | 1. [编写第一个 async/await 函数](https://github.com/wangshijun/course-javascript-async-await/blob/master/01-first-async-await-function.js) 65 | 1. [将 async 函数用在 Promise chain 中](https://github.com/wangshijun/course-javascript-async-await/blob/master/02-use-async-function-as-promise.js) 66 | 1. [把任意类型的函数转成 async 风格](https://github.com/wangshijun/course-javascript-async-await/blob/master/03-convert-any-function-into-async.js) 67 | 1. [处理 async 函数中的错误](https://github.com/wangshijun/course-javascript-async-await/blob/master/04-handling-errors-for-async.js) 68 | 1. [正确处理多个 await 操作的并行串行](https://github.com/wangshijun/course-javascript-async-await/blob/master/05-await-multiple-promise-seq-or-concurrently.js) 69 | 1. [使用 Promise.all() 让多个 await 操作并行](https://github.com/wangshijun/course-javascript-async-await/blob/master/06-await-multiple-promise-with-all.js) 70 | 1. [结合 await 和任意兼容 .then() 的代码](https://github.com/wangshijun/course-javascript-async-await/blob/master/07-use-await-with-any-thenable.js) 71 | 1. [在 for 循环中正确的使用 await](https://github.com/wangshijun/course-javascript-async-await/blob/master/08-await-in-loops.js) 72 | 73 | ## 运行环境 74 | 75 | * Node.js v8.6.0 76 | * VSCode v1.17.1 + Vim 77 | 78 | ## 参考资料 79 | 80 | * [Google Web Fundamentals](https://developers.google.com/web/fundamentals/getting-started/primers/async-functions) 81 | 82 | ## 视频下载 83 | 84 | 关注《前端周刊》微信公众号,回复 course-async-await 即可获取高清视频教程下载地址。 85 | 86 | ![README.png](./README.png) 87 | 88 | ## 题外话 89 | 90 | 最后,可能你有同学会问,我为什么要做这个公开课?接下来的计划是什么?请阅读[好久不见,我总感觉欠你点什么](https://mp.weixin.qq.com/s/sH3jpHb7ry2_fF3OVrQ72Q) 91 | --------------------------------------------------------------------------------