在最开始的时候, js 异步编程是一件很痛苦的事, 不过随着技术发展, 现在写异步已经可以像写同步一样舒服了.
主要的变化过程:
回调函数 ===>>> promise ===>>> generater ===>>> async/await
回调函数时代
dosomething(sucessCallback, errCallback)
这种写法在多重异步处理的时候很容易出现回调地狱
promise 写法
promise 最大的好处就是实现了链式调用的写法, 而且可以用 catch 来捕获异常.
不过 Promise 对象的错误具有 "冒泡" 性质, 会一直向后传递, 直到被捕获为止; 而且 promise 会吞掉错误, 不向外部抛出
- const getJSON = function(url) {
- const promise = new Promise(function(resolve, reject){
- const handler = function() {
- if (this.readyState !== 4) {
- return;
- }
- if (this.status === 200) {
- resolve(this.response);
- } else {
- reject(new Error(this.statusText));
- }
- };
- });
- return promise;
- };
- getJSON("/posts.json").then(function(json) {
- console.log('Contents:' + json);
- }).catch(err => console.log(err));
generator 写法
Generator 函数是协程在 ES6 的实现, 最大特点就是可以交出函数的执行权, 注意它不是语法糖.
第一步, 协程 A 开始执行.
第二步, 协程 A 执行到一半, 进入暂停, 执行权转移到协程 B.
第三步,(一段时间后) 协程 B 交还执行权.
第四步, 协程 A 恢复执行.
- function* gen(x) {
- var y = yield x + 2;
- return y;
- }
- var g = gen(1);
- g.next() // { value: 3, done: false }
- g.next() // { value: undefined, done: true }
- g.throw('出错了');
yield 之后的跟随的对象或基本类型的值会被自动转化为 promise.
generator 最麻烦的就是需要自己运行 next 去执行下一步
async/await 写法
这是 generator+co 库的一个 es7 语法糖, 最接近同步的语法.
由于 generator 需要不断地执行, 于是有人写了一个叫 co 的自执行函数库.
- var co = require('co');
- co(gen);
这样 generator 就可以自动地执行了. 于是就出现了 async/await 的写法:
- async function getStockPriceByName(name) {
- const symbol = await getStockSymbol(name);
- const stockPrice = await getStockPrice(symbol);
- return stockPrice;
- }
- getStockPriceByName('goog').then(function (result) {
- console.log(result);
- });
async 后面的函数返回的是一个 promise 对象, 可以用. then 的语法.
- try {
- getStockPriceByName()
- } catch(err) {
- console.log(error)
- } finally {
- dosomething()
- }
错误处理方面也更加接近同步的语法.
总结
只要能够写 es6 语法, 我们就可以用上 async/await 的语法来解决异步编程的需要了, 这是将会是相当方便的一个体验, 也会给后续的人一个更清晰的代码逻辑.
来源: https://juejin.im/post/5af64ae96fb9a07acd4dcba0