Async/Await

理解的还是不透彻,只是抄录了别人的文章。。。。。

async

ES2017 标准引入了 async 函数,使得异步操作变得更加方便。

async 函数是什么?一句话,它就是 Generator 函数的语法糖。

async 函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。

(async function () {
    return '我是Promise'
})()
// 返回是Promise
//Promise {<resolved>: "我是Promise"}

你会发现返回是这个:Promise {: "我是Promise"}。

自动解析成 Promise.resolve(‘我是Promise’);

等同于:

(async function () {
    return Promise.resolve('我是Promise');
})()

所以你想像一般function的返回那样,拿到返回值,原来的思维要改改了!你可以这样拿到返回值:

const demo = async function () {
    return Promise.resolve('我是Promise');
    // 等同于 return '我是Promise'
    // 等同于 return new Promise((resolve,reject)=>{ resolve('我是Promise') })
}
demo.then(result=>{
    console.log(result) // 这里拿到返回值
})

demo

async function timeout( ) {
    return 'hello world'
}
timeout();
console.log('虽然在后面,但是我先执行');
async function testAsync( ) {
  return 'hello async';
}

testAsync().then((v) => {
  console.log(v);    // 输出 "hello async"
});

如果 async 函数没有返回值,它会返回 Promise.resolve(undefined)。

await

await 命令只能用在 async 函数之中,如果用在普通函数,就会报错。

async 函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而 await 命令就是内部 then 命令的语法糖。

await 的本质是可以提供等同于”同步效果“的等待异步返回能力的语法糖

await 表达式会 暂停 当前 async function 的执行,等待 Promise 处理完成。若 Promise 正常处理(fulfilled),其回调的resolve 函数参数作为 await 表达式的值,继续执行 async function。

await 休眠效果

JavaScript 一直没有休眠的语法,但是借助await命令就可以让程序停顿指定的时间。

function sleep(interval) {
  return new Promise(resolve => {
    setTimeout(resolve, interval);
  })
}

// 用法
async function one2FiveInAsync() {
  for(let i = 1; i <= 5; i++) {
    console.log(i);
    await sleep(1000);
  }
}

one2FiveInAsync();

async/await 的优势

优势在于处理 then 链

假设一个业务,分多个步骤完成,每个步骤都是异步的,而且依赖于上一个步骤的结果。

/** * 传入参数 n,表示这个函数执行的时间(毫秒) * 执行的结果是 n + 200,这个值将用于下一步骤 */
function takeLongTime(n) {
  return new Promise(resolve => {
    setTimeout(() => resolve(n + 200), n);
  });
}

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

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

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

现在用 Promise 方式来实现这三个步骤的处理

function doIt( ) {
    console.time('doIt');
    const time1 = 300;
    step1(time1)
      .then(time2 => step2(time2))
      .then(time3 => step3(time3))
      .then(result => {
        console.log(`result is ${result}`);
        console.timeEnd('doIt');
      });
}

doIt();

// step1 with 300
// step2 with 500
// step3 with 700
// result is 900
// doIt: 1503.638916015625ms

如果用 async/await 来实现呢,会是这样:

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

doIt();

async/await 执行顺序题

async function async1( ){
  console.log('async1 start');
  await async2();
  console.log('async1 end');
}
async function async2( ){
  console.log('async2');
}
async1();
console.log('i am koala');

正确的执行顺序

"async1 start"
"async2"
"i am koala"
"async1 end"

执行到 async1 这个函数时,首先会打印出 “async1 start”(async 表达式定义的函数也是立即执行的);

await async2(),发现 async2 也是个 async 定义的函数,所以直接执行了“console.log(‘async2’)”,同时async2返回了一个Promise,划重点:此时返回的Promise会被放入到回调队列中等待,await会让出线程(js是单线程还用我介绍吗),接下来就会跳出 async1函数 继续往下执行。

promise、async和await的执行顺序

promise、async和await之执行顺序的那点事

详解promise、async和await的执行顺序

async function async1(){
    console.log('async1 start')
    await async2()
    console.log('async1 end')
}
async function async2(){
    console.log('async2')
}
console.log('script start')
setTimeout(function(){
    console.log('setTimeout') 
},0)  
async1();
new Promise(function(resolve){
    console.log('promise1')
    resolve();
}).then(function(){
    console.log('promise2')
})
console.log('script end')

正确答案

script start
async1 start
async2
promise1
script end
promise2
async1 end
setTimeout

知识点

显然,这考察的是 js 中的事件循环和回调队列。注意以下几点:

  • Promise 优先于s etTimeout 宏任务。所以,setTimeout 回调会在最后执行。
  • Promise 一旦被定义,就会立即执行。
  • Promise 的 reject 和 resolve 是异步执行的回调。所以,resolve() 会被放到回调队列中,在主函数执行完和 setTimeout 前调用。
  • await 执行完后,会让出线程。async 标记的函数会返回一个 Promise 对象

解题

执行到 async1 这个函数时,首先会打印出“async1 start”(这个不用多说了吧,async 表达式定义的函数也是立即执行的);

然后执行到 await async2(),发现 async2 也是个 async 定义的函数,所以直接执行了“console.log(‘async2’)”,同时async2返回了一个Promise,划重点:此时返回的Promise会被放入到回调队列中等待,await会让出线程(js是单线程还用我介绍吗),接下来就会跳出 async1函数 继续往下执行。

然后执行到 new Promise,前面说过了promise是立即执行的,所以先打印出来“promise1”,然后执行到 resolve 的时候,resolve这个任务就被放到回调队列中(前面都讲过了上课要好好听啊喂)等待,然后跳出Promise继续往下执行,输出“script end”。

接下来是重头戏。同步的事件都循环执行完了,调用栈现在已经空出来了,那么事件循环就会去回调队列里面取任务继续放到调用栈里面了。

这时候取到的第一个任务,就是前面 async1 放进去的Promise,执行Promise时发现又遇到了他的真命天子resolve函数,划重点:这个resolve又会被放入任务队列继续等待,然后再次跳出 async1函数 继续下一个任务。

接下来取到的下一个任务,就是前面 new Promise 放进去的 resolve回调 啦 yohoo~这个resolve被放到调用栈执行,并输出“promise2”,然后继续取下一个任务。

后面的事情相信你已经猜到了,没错调用栈再次空出来了,事件循环就取到了下一个任务:历经千辛万苦终于轮到的那个Promise的resolve回调!!!执行它(啥也不会打印的,因为 async2 并没有return东西,所以这个resolve的参数是undefined),此时 await 定义的这个 Promise 已经执行完并且返回了结果,所以可以继续往下执行 async1函数 后面的任务了,那就是“console.log(‘async1 end’)”。

谜之困惑的那两句执行结果(“promise2”、“async1 end”)就是这样来的~

await命令放在try…catch代码块中

async function myFunction() {
  try {
    await somethingThatReturnsAPromise();
  } catch (err) {
    console.log(err);
  }
}

// 另一种写法

async function myFunction() {
  await somethingThatReturnsAPromise()
  .catch(function (err) {
    console.log(err);
  });
}

more

-https://blog.csdn.net/CSDN_KONGlX/article/details/125631279