如果你使用的是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