如果你使用的是Typescript>1.7,或者NodeJS>7.6, 那么你就已经可以使用新的async/await语法来部分代替原来的promise写法了。
先来看一个最简单的例子
Promise写法:
doSomethingWithPromise(): Promise<string> {
return Promise.resolve("success");
}
doSomethingWithPromise().then(result=>console.log(`result is ${result}`));// result is success
aysnc/await写法:
async doSomething(){
return Promise.resolve("success");
}
let result = await doSomething();
console.log(`result is ${result}`);// result is success
网上基本所有的关于async/await的例子都差不多这个意思。
怎么样,把代码从异步回调地狱里面解救出来了吧。类似同步代码的感觉是不是让你蠢蠢欲动,把以前所有的代码都翻新成async/await?(事实上只能翻新Server端的,浏览器现在还不全部支持)
然而你会很快面对一个事实:即使你有了async/await,以同步风格编写代码有时是不可能的,至少不是简单的。
给我一个例子:
假设我们要做一个批萨,大概有以下步骤:
- 做饼(dough)
- 做酱(sauce)
- 尝一下酱,根据口味决定放什么样的奶酪(cheese)
让我们先直接用async/await随便写一个,代码如下:
async function makePizza(sauceType = 'red') {
let dough = await makeDough();
let sauce = await makeSauce(sauceType);
let cheese = await grateCheese(sauce.determineCheese());
dough.add(sauce);
dough.add(cheese);
return dough;
}
这个代码足够简单,逻辑简单明了,先做饼,再做酱,然后决定奶酪。只有一个问题:我们把所有的事情线性一个一个做了,我们应该允许JavaScript引擎并行的跑这些任务!
所以,现在我们的代码是这样跑的:
|-------- dough --------> |-------- sauce --------> |-- cheese -->
然后我们期望我们的代码能这样跑:
|-------- dough -------->
|-------- sauce --------> |-- cheese -->
所以,我们可以改进下我们的代码:
async function makePizza(sauceType = 'red') {
let [ dough, sauce ] = await Promise.all([makeDough(), makeSauce(sauceType)]);
let cheese = await grateCheese(sauce.determineCheese());
dough.add(sauce);
dough.add(cheese);
return dough;
}
恩,比上个版本好一点了,虽然我们用到了Promise.all
来并行出发2个任务。但是仔细想想,如果做饼和做酱的时间不一样长呢?比如做酱的时间要远远短于做饼的时间?结果就会变成这样:
|-------- dough -------->
|--- sauce ---> |-- cheese -->
实际上决定奶酪这件事情,在酱做好之后就能直接做了,不需要等待饼做完。
让我们尝试完全用Promise来解决这个问题:
function makePizza(sauceType = 'red') {
let doughPromise = makeDough();
let saucePromise = makeSauce(sauceType);
let cheesePromise = saucePromise.then(sauce => {
return grateCheese(sauce.determineCheese());
});
return Promise.all([ doughPromise, saucePromise, cheesePromise ])
.then(([ dough, sauce, cheese ]) => {
dough.add(sauce);
dough.add(cheese);
return dough;
});
}
执行的结果应该就是我们期望的:
|--------- dough --------->
|---- sauce ----> |-- cheese -->
我们可以尝试把代码改成async/await风格的:
async function makePizza(sauceType = 'red') {
let doughPromise = makeDough();
let saucePromise = makeSauce(sauceType);
let sauce = await saucePromise;
let cheese = await grateCheese(sauce.determineCheese());
let dough = await doughPromise;
dough.add(sauce);
dough.add(cheese);
return dough;
}
然而,你一定注意到了我们必须先建好饼和酱的Promise并执行他们,再调用await来同步的获取执行结果。恩,这种写法其实比纯promise的写法没有高明到哪里去。。。
总结:即使你准备使用async/await,你仍然需要彻底了解Promise的机制和原理,必要的时候,不要犹豫使用Promise