ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Javascript之简单理解async/await

2020-12-06 15:05:38  阅读:182  来源: 互联网

标签:function await console log Javascript resolve async


什么是async?什么是await?

JavaScript的世界,同步sync异步async的爱恨情仇,就如同偶像剧一般的剪不断理还乱,特别像是setTimeoutsetIntervalMLHttpRequestfetch这些同步、异步混杂的用法,都会让人一个头两个大,幸好ES6出现了promiseES7出现了async、await,帮助我们可以更容易的进行代码逻辑的撰写。

对于同步和异步理解,使我觉得比较好理解的方法:「同一个跑道vs不同跑道」,透过跑步的方式,就更容易明白同步和异步。

  • 同步:在「同一个跑道」比赛「接力赛跑」,当棒子没有交给我,我就得等你,不能跑。
  • 异步:在「不(非)同跑道」比赛「赛跑」,谁都不等谁,只要轮到我跑,我就开始跑。

简单理解JavaScript Async 和Await

ES7async的本质是promise的语法糖,只要function标记为async,就表示里头可以撰写await的同步语法,而await顾名思义就是「等待」,它会确保一个promise函数都执行到解决(resolve )或出错( reject)后才会进行下一步,当async function的内容全都结束后,会返回一个promise,这表示后方可以使用.then语法来做连接,基本的代码就像下面这样:

async function a(){
  await b();
  .....       // 等 b() 完成後才會執行
  await c();
  .....       // 等 c() 完成後才會執行
  await new Promise(resolve=>{
    .....
  });
  .....       // 上方的 promise 完成後才會執行
}
a();
a().then(()=>{
  .....       // 等 a() 完成後接著執行
});

利用async 和await 做个「漂亮的等待」

比较了解asyncawait的意思之后,就来试试看做个「漂亮的等待」,使用ES6promise来实现delay (如同下方的代码范例) ,这个delay透过.then来完成一步一步的串接,虽然逻辑上很清楚,但若要实作比较复杂的流程,就得把每个代码写在对应的callback里,也就没有想像的容易,这就是「不太漂亮的等待」 (使用setTimeout的做法就是不漂亮的等待)。

const delay = (s) => {
  return new Promise(resolve => {
    setTimeout(resolve,s); 
  });
};

delay().then(() => {
  console.log(1);     // 顯示 1
  return delay(1000); // 延遲ㄧ秒
}).then(() => {
  console.log(2);     // 顯示 2
  return delay(2000); // 延遲二秒
}).then(() => {
  console.log(3);     // 顯示 3
});

如果我们把上面的代码修改为asyncawait的写法,突然就发现代码看起来非常的干净,因为await会等待收到resolve之后才会进行后面的动作,如果没有收到就会一直处在等待的状态,所以什么时候该等待,什么时候该做下一步,就会非常清楚明了,这也就是我所谓「漂亮的等待」。

注意,await一定得运行在async function 内!

~async function{           // ~ 開頭表示直接執行這個 function,結尾有 ()
  const delay = (s) => {
    return new Promise(function(resolve){  // 回傳一個 promise
      setTimeout(resolve,s);               // 等待多少秒之後 resolve()
    });
  };

  console.log(1);      // 顯示 1
  await delay(1000);   // 延遲ㄧ秒
  console.log(2);      // 顯示 2
  await delay(2000);   // 延遲二秒
  console.log(3);      // 顯示 3
}();

搭配Promise

基本上只要有asyncawait 的地方,就一定有promise的存在,promise顾名思义就是「保证执行之后才会做什么事情」,刚刚使用了asyncawaitpromise改善setTimeout这个容易出错的异步等待,针对setInterval,也能用同样的做法修改

举例来说,下面的代码执行之后,并「不会」如我们预期的「先显示1,再显示haha0...haha5 ,最后再显示2」,而是「先显示12,然后再出现haha0...haha5」,因为虽然代码逻辑是从上往下,但在count function里头是异步的语法,导致自己走自己的路,也造成了结果的不如预期。

const count = (t,s) => {
  let a = 0;
  let timer = setInterval(() => {
    console.log(`${t}${a}`);
    a = a + 1;
    if(a>5){
      clearInterval(timer);
    }
  },s);
};

console.log(1); 
count('haha', 100);
console.log(2);

这时我们可以透过async、awaitpromise进行修正,在显示1之后,会「等待count function结束后再显示2

~async function(){  
  const count = (t,s) => {
      return new Promise(resolve => {
        let a = 0;
        let timer = setInterval(() => {
          console.log(`${t}${a}`);
          a = a + 1;
          if(a>5){
            clearInterval(timer);
            resolve();  // 表示完成
          }
        },s);
      });
    };

  console.log(1); 
  await count('haha', 100);
  console.log(2);
}();

简单理解JavaScript Async 和Await

链式调用

假设一个业务,分多个步骤完成,每个步骤都是异步的,而且依赖于上一个步骤的结果。我们仍然用 setTimeout 来模拟异步操作:

/**
 * 传入参数 n,表示这个函数执行的时间(毫秒)
 * 执行的结果是 n + 100,这个值将用于下一步骤
 */
function takeLongTime(n) {
    return new Promise(resolve => {
        setTimeout(() => resolve(n + 100), 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 init() {
    console.time("start init");
    const time1 = 100;
    step1(time1)
        .then(time2 => step2(time2))
        .then(time3 => step3(time3))
        .then(result => {
            console.log(`result is ${result}`);
            console.timeEnd("end init");
        });
}

init();

// step1 with 100
// step2 with 200
// step3 with 300
// result is 400

async awit实现

async function init() {
    console.time("start init");
    const time1 = 100;
    const time2 = await step1(time1);
    const time3 = await step2(time2);
    const result = await step3(time3);
    console.log(`result is ${result}`);
    console.timeEnd("end init");
}

init();

结果和之前的 Promise 实现是一样的,但是这个代码看起来是不是清晰得多

关于文中几个知识点概念

setTimeout()

方法用于在指定的毫秒数后调用函数或计算表达式。

function fn1(){
			console.log("你好");
		}
setTimeout(fn1,3000);

setInterval()

每隔一段时间执行一次指定的语句或函数,是个重复性的操作。

setInterval(fn1,8000); 

小结

坦白说只要你一但熟悉了asyncawait,就真的回不去了,虽然说callback 仍然是代码开发里必备的功能,但对于同步和异步之间的转换,以后就交给asyncawait来处理吧!

标签:function,await,console,log,Javascript,resolve,async
来源: https://blog.csdn.net/m0_37903882/article/details/110733520

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有