深入理解异步、Promise、Async & Await

导入例子

同步阻塞:老王用水壶煮水,站在那里看水什么时候开
同步非阻塞:老王用水壶煮水,跑到客厅看电视,每隔一段时间过来看看水开没
异步阻塞:老王用响水壶煮水,站在那里等着响水壶通知自己水开
异步非阻塞:老王用响水壶煮水,跑到客厅看电视,等待响水壶通知自己水开

同步与异步:同步一般指主动请求并等待I/O操作完毕的方式。异步一般指主动请求后可以继续处理其他任务,随后等待I/O操作完毕的通知(响水壶)

阻塞和非阻塞:讨论的角度是线程是否被阻塞,非阻塞就是煮水的过程中无法去干别的事,非阻塞就是在同样的情况下可以去干别的事

详解异步

异步的出现是为了解决同步阻塞的问题,也就是一行一行执行指令的,当遇到某个指令需要耗费大量时间的时候,后面的指令就无法执行,这种同步执行的操作容易使页面呈卡死状态

callback、Ajax、Promise、async await、nextTick()
不进入主线程、而进入"任务队列"的任务,只有等主线程任务执行完毕,"任务队列"开始通知主线程,请求执行任务,该任务才会进入主线程执行

JS队列 & 执行优先级

  • 主线程:JS只有一个线程,这个线程负责解释和执行JS代码,称其为主线程,在这个主线程上,所有的代码按照顺序执行
  • 消息队列:消息队列里面放的是一些待触发执行的方法,如点击事件,当触发之后,会被通知主线程去执行
  • 任务队列:同步代码放到执行栈中执行,异步代码会先存放到任务队列中,执行栈代码先执行,异步代码在执行栈执行完后再执行。任务队列优先级高于消息队列
  • 延迟函数执行(setTimeout、setInterval):等到执行栈清空的时候才会执行

异步任务中又分为宏任务和微任务两种

  • 微任务(Promise、async/await、process.nextTick):执行完当前主线程任务后就要马上执行的任务
  • 宏任务(setTimeout、setInterval、Ajax、事件绑定):可以理解是每次执行栈执行的代码就是一个宏任务

Js不存在异步,可以通过事件轮询实现异步,是单线程的。
JS的宿主环境(浏览器,node)存在异步,是多线程的。

优先级:同步>异步(任务队列>消息队列)>延迟函数
先同步后异步,异步分宏任务、微任务,同级先微后宏

 - new Promise是一个构造函数,是同步任务  
 - Promise.resolve().then 是微任务
 - async是同步任务
 - await方法返回的是一个Promise对象,后面相当于Promise then, 是微任务
 - 定时器,加入下一次宏任务,是宏任务

Promise

  • Promise的创建和初始化是同步的(本身是构造函数)
  • Promise的回调(通过then、catch、finally等方法)是异步执行的
const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    const randomNumber = Math.random();
    if (randomNumber > 0.5) {
      resolve(randomNumber);
    } else {
      reject("Error: Number is too small");
    }
  }, 1000);
});

myPromise
  .then((result) => {
    console.log("Success:", result);
  })
  .catch((error) => {
    console.log("Error:", error);
  });

创建Promise对象的时候传递的参数是一个执行器函数,参数是resolvereject,操作成功时传递resolve中的结果,操作失败时传递reject中的结果

使用then() 方法可以处理 Promise 对象成功的情况)Promise状态变为fulfilled时),接受一个回调函数作为参数,回调函数的参数就是异步操作的结果。使用 catch() 方法可以处理 Promise 对象失败的情况,接受一个回调函数作为参数,回调函数的参数是错误信息。

console.log('Start'); 

const promise = new Promise((resolve, reject) => {
  console.log('Promise executor');
  setTimeout(() => {
    resolve('Done');
  }, 1000);
});

promise.then(result => {
  console.log(result);
});

console.log('End');

1. 主线程:Start
2. 主线程:构造函数new 创建实例时自动执行,Promise的构造和初始化是同步的
3. setTimeout 等主线程清空时再执行
4. promise.then()创造异步回调函数,等待Promise状态变为fulfilled后再执行 (异步微任务)
5. 主线程:End
6. 主线程清空,1s后执行setTimeout
7. ,执行resolve,将微任务队列的回调函数执行


输出:
Start
Promise executor
End
Done




Async & Await

async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。

Async

async 的作用就是让函数return一个new promise把async里面的内容包住(里面是同步的)。resolve、reject把值传递给then(), catch() 回调异步函数,只有async函数内部执行完所有同步操作/return/抛出错误后,才会改变Promise的状态执行对应的then/catch回调

Promise 的解决时机
在 async 函数中,Promise 的解决发生在函数体内的同步代码执行完毕时
这意味着,即使函数体内还有未完成的异步操作(如 setTimeout),Promise 也会被解决。

Await

await的意思是等待后面表达式的结果,所以意思就是立即执行await后面的表达式,然后.then{ await后面的语句}。

await命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。await命令就是内部then命令,后面的内容是回调函数

任何一个await语句后面的 Promise 对象变为reject状态,那么整个async函数都会中断执行。

有时,我们希望即使前一个异步操作失败,也不要中断后面的异步操作。这时可以将第一个await放在try…catch结构里面,这样不管这个异步操作是否成功,第二个await都会执行。

await异步操作可以同步声明

// 写法一
let [foo, bar] = await Promise.all([getFoo(), getBar()]);

// 写法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;```
// Async 
console.log('aaa');
 
(async ()=>{
  console.log(111);  //在async里面
})().then(()=>{
  console.log(222);  //在async的then里面
});
 
console.log('bbb');

输出:
aaa 111 bbb 222
// Await
console.log('aaa');
 
(async ()=>{
  console.log(111);
  await console.log(222);
  console.log(333);
})().then(()=>{
  console.log(444);
});
 
console.log('ddd');

输出:
aaa 111 222 ddd 333 444 
console.log('aaa');

setTimeout(()=>console.log('t1'), 0);
 
 
(async ()=>{
  console.log(111);
  await console.log(222);
  console.log(333);
 
  setTimeout(()=>console.log('t2'), 0)
  })().then(()=>{
  console.log(444);
  })
  
console.log('bbb');

输出:
aaa  111 222 bbb 333 444 t1 t2
虽然要执行setTimeout才能进入then,但是

setTimeout(function(){  
 console.log('1') 
}); 
 
 
 new Promise(function(resolve){ 
    console.log('2')
    for (var i = 0; i < 10000; i++){ 
       i == 99 && resolve()
    }}).then(function(){ 
    console.log('3')}
    )
 
 
 console.log('4');

输出:
 2 4  3 1




 //执行顺序
   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
asncy2 .
promise1
script end
async1 end
promose2
setTimeout


深入理解JS异步系列
阮一峰async
理解练习异步题

  • 18
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值