在 MDN 的 JavaScript 系列中咱们已经学习了 callback、promise、generator、async/await。而在这一篇文章中,做者将以实际样例阐述异步发展历史,介绍每种实现方式的优点与不足,以期帮助读者熟悉历史进程并把握异步发展的脉络。 javascript
几十年前的导航网站,清爽又简单,没有什么特别的功能,只是单纯的展现,现成的网页在服务器上静静躺着,高效毫无压力,让人很喜欢。html
几十年后的今天,静态页面远不能知足用户的需求,网站变得复杂起来,用户交互愈来愈频繁,从而产生大量复杂的内部交互,为了解决这种复杂,出现了各类系统“模式”,从而很容易的在外部获取数据,并实时展现给用户。java
获取外部数据实际上就是“网络调用”,这个时候“异步”这个词汇出现了。编程
异步指两个或两个以上的对象或事件不一样时存在或发生(或多个相关事物的发生无需等待其前一事物的完成)
异步 callbacks其实就是函数,只不过是做为参数传递给那些在后台执行的其余函数。当那些后台运行的代码结束,就调用 callbacks 函数,通知你工做已经完成,或者其余有趣的事情发生了。
场景segmentfault
let readFile = (path, callBack) => { setTimeout(function () { callBack(path) }, 1000) } readFile('first', function () { console.log('first readFile success') readFile('second', function () { console.log('second readFile success') readFile('third', function () { console.log('third readFile success') readFile('fourth', function () { console.log('fourth readFile success') readFile('fifth', function () { console.log('fifth readFile success') }) }) }) }) })
优势:promise
缺点:服务器
一个 Promise对象表明一个在这个 promise 被建立出来时不必定已知的值。它让您可以把异步操做最终的成功返回值或者失败缘由和相应的处理程序关联起来。 这样使得异步方法能够像同步方法那样返回值:异步方法并不会当即返回最终的值,而是会返回一个 promise,以便在将来某个时候把值交给使用者。
场景网络
let readFile = (path) => { return new Promise((resolve, reject) => { setTimeout(() => { if (!path) { reject('error!!!') } else { console.log(path + ' readFile success') resolve() } }, 1000) }) } readFile('first') .then(() => readFile('second')) .then(() => readFile('third')) .then(() => readFile('fourth')) .then(() => readFile('fifth'))
优势:异步
缺点:async
Generator函数是 ES6 中提供的一种 异步编程解决方案。语法上,首先能够把它理解成, Generator函数是一个 状态机,封装了多个内部状态,须要使用 next()函数来继续执行下面的代码。
特征
场景
var readFile = function (name, ms) { return new Promise((resolve, reject) => { setTimeout(() => { console.log(name + '读完了') resolve() }, ms) }) } var gen = function* () { console.log('指定generator') yield readFile('first', 1000) yield readFile('second', 2000) yield readFile('third', 3000) yield readFile('forth', 4000) yield readFile('fifth', 5000) return '完成了' } var g = gen() var result = g.next() result.value .then(() => { g.next() }) .then(() => { g.next() }) .then(() => { g.next() }) .then(() => { g.next() })
优势:
缺点:
async functions 和 await 关键字是最近添加到 JavaScript 语言里面的。它们是 ECMAScript 2017 JavaScript 版的一部分(参见 ECMAScript Next support in Mozilla)。简单来讲,它们是基于 promises 的语法糖,使异步代码更易于编写和阅读。经过使用它们,异步代码看起来更像是老式同步代码,所以它们很是值得学习。
场景 1
var readFile = function (name, ms) { return new Promise((resolve, reject) => { setTimeout(() => { console.log(name + '读完了') resolve() }, ms) }) } async function useAsyncAwait() { await readFile('first', 1000) await readFile('second', 2000) await readFile('third', 3000) await readFile('forth', 4000) await readFile('fifth', 5000) console.log('async文件阅读完毕') } useAsyncAwait()
优势
语义更清晰、简洁
缺点
场景 2 场景 1 中的代码,其实 second,third 的伪请求其实并不依赖于 first,second 的结果,但它们必须等待前一个的完成才能继续,而咱们想要的是它们同时进行,因此正确的操做应该是这样的。
async function useAsyncAwait() { const first = readFile('first', 1000) const second = readFile('second', 2000) const third = readFile('third', 3000) const forth = readFile('forth', 4000) const fifth = readFile('fifth', 5000) console.log('async文件阅读完毕') await first await second await third await forth await fifth } useAsyncAwait()
在这里,咱们将三个 promise 对象存储在变量中,这样能够同时启动它们关联的进程。
在这篇文章中,咱们已经介绍了 JavaScript 异步发展史中 --- callback、promise、generator、async/await 的使用方式、优势与缺点。
发展史 | 优势 | 缺点 |
---|---|---|
callback | 解决了同步问题 | 回调地狱、可读性差、没法 try / catch 、没法 return |
promise | 必定程度上解决了回调地狱的可读性 | 没法取消、任务多时,一样存在语义不清晰 |
generator | 能够控制函数的执行,能够配合 co 函数库使用 | 流程管理却不方便(即什么时候执行第一阶段、什么时候执行第二阶段 |
async/await | 语义更清晰、简洁,内置执行器 | 认知不清晰可能会形成大量 await 阻塞(程序并不会等在原地,而是继续事件循环,等到响应后继续往下走)状况 |
而在现有的异步解决方案中,async/await 是使用人数最多的,它带给咱们最大的好处即同步代码的风格,语义简洁、清晰。