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