js异步编程发展

872 阅读2分钟

在最开始的时候,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的语法来解决异步编程的需要了,这是将会是相当方便的一个体验,也会给后续的人一个更清晰的代码逻辑。