Back

es6 - 看这个就够了- 超级重要! async 与 await的使用。promise.then的升级版

发布时间: 2018-12-24 07:18:00

参考;http://es6.ruanyifeng.com/#docs/async

我们可以认为async+ await是  promise..then的升级版。 

想使用 async + await, 一定要先知道  promise . then ..的用法(看下面)

总结:

1. async用来修饰function , 

2. await 只能用在 async 函数中, 用来声名该statement是个异步操作。(顺序执行)

3. 所有写在 async函数中的语句(无论是否是await),都是一行一行代码顺序执行的。 

4. async 函数调用的 await语句必须是个return new Promise()的函数,并且,在new Promise( (resolve) ) 中要 指定resolve是啥,

new Promise().then的用法:

    // Promise 有三种状态: resove (正常) , reject (出错) , pending ( 运行中)

    let result = new Promise( (resolve, reject ) => {
        let result = 0
        setTimeout( () => {
            console.info("sleep n ms...")
            result = 200
            resolve(result)   // 注意,这里的 resolve, 就相当于是返回了。
        }, 3000)
    })

    // 运行
    result.then( (temp) => {
        console.info("result : ", temp)
    })

下面是个超级简单的例子: (async, await , 与 Promise()一起使用)

    // 注意这里是普通函数
    function sleep() {
        // 注意这里要return 
        return new Promise( (resolve) => {
            setTimeout(() => {
                resolve("abc")   // 注意这里必须要 resolve
            }, 1500)
        })
    }

    // 注意: 这里使用了  async.
    async function get_result_after_sleep(){
        console.info("== now in get_result_after_sleep")
        let result = await sleep()   // 这里要获得 result,  就是 sleep()函数中的 resolve() 出来的结果
        console.info("== result: ", result)
    }

    get_result_after_sleep()

我们看一个 例子(promise + then)

function delayedPrint(time){
  console.info( (Date.now() / 1000) + "== 延迟 "+ time + "ms 后开始打印")
  return new Promise( resolve => {
    setTimeout( () =>{
      resolve(time + 500)
    }
    ,time)
  })
}

delayedPrint(2000).then( () => {
  console.info((Date.now() / 1000) + "== hello!")
})

运行结果:

1545636482.144== 延迟 2000ms 后开始打印
1545636484.148== hello!

可以把上面的代码写成:

function delayedPrint(time){
  console.info( (Date.now() / 1000) + "== 延迟 "+ time + "ms 后开始打印")
  return new Promise( resolve => {
    setTimeout( () =>{
      resolve(time + 500)
    }
    ,time)
  })
}

// 定义了一个封装后的方法: async ...
async function print(){

  // 调用该方法时, 传入一个参数就好了。resolver 不用传 
  await delayedPrint(2000)

  // 这一行代码就是resolver的实现
  console.info((Date.now() / 1000) + "== hello!")
}

// 最后,调用这个 async方法
print()

 效果是一样的。

$ node test_async.js
1545636670.899== 延迟 2000ms 后开始打印
1545636672.902== hello!

为什么使用它。

回答: 为了避免 callback hells (回调地狱)。(参考https://segmentfault.com/a/1190000007535316) 我们看下面的代码:

function step1(n) {
    console.log(`step1 with ${n}`);
    return takeLongTime(n);
}

function step2(m, n) {
    console.log(`step2 with ${m} and ${n}`);
    return takeLongTime(m + n);
}

function step3(k, m, n) {
    console.log(`step3 with ${k}, ${m} and ${n}`);
    return takeLongTime(k + m + n);
}

上面的代码中,每一步的参数,都是上一次的结果, 例如 step2的参数 之一是step1的结果。 step3的参数是step2, step1的结果。如果用promise then来写的话:

function doIt() {
    console.time("doIt");
    const time1 = 300;
    step1(time1)
        .then(time2 => {
            return step2(time1, time2)
                .then(time3 => [time1, time2, time3]);
        })
        .then(times => {
            const [time1, time2, time3] = times;
            return step3(time1, time2, time3);
        })
        .then(result => {
            console.log(`result is ${result}`);
            console.timeEnd("doIt");
        });
}

doIt();

可以看出非常麻烦, 但是用 await/async来写就特别舒服

async function doIt() {
    console.time("doIt");
    const time1 = 300;
    const time2 = await step1(time1);
    const time3 = await step2(time1, time2);
    const result = await step3(time1, time2, time3);
    console.log(`result is ${result}`);
    console.timeEnd("doIt");
}

doIt();

上面的代码看起来比较乱,看这个简单版

Back