异步题目解析

为什么要异步?

场景描述:

如果JS中不存在异步,只能自上而下执行,如果上一行解析时间很长,那么下面的代码就会被阻塞。
对于用户而言,阻塞就意味着"卡死",这样就导致了很差的用户体验

就是为了把费时间的事情放在一旁去做,我们先去做其他的事情,然后做完之后,我们在把异步处理之后的结果直接拿来用。

这不就是以前的时间分配吗?

洗菜,切菜,洗衣服(洗衣机),洗衣服(人放衣服),洗衣服(人收衣服),煮饭(电饭煲)……

怎么样在最大时间内完成这些任务。

主线程就是人,异步线程就是那些机器,帮我们做了,我们可以去做其他的事情。

所以一般异步用来干嘛??

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
复杂题目
async function async0() {
  console.log('async0 start')
  async1()
  console.log('async0 end')
}
async function async1() {
  console.log('async1 start')
  await async2()
  console.log('async1 end')
  await async5()
}
async function async2() {
  console.log('async2')
  await async3()
  await async4()
}
async function async3() {
  console.log('async3')
}
async function async4() {
  console.log('async4')
}
async function async5() {
  console.log('async5')
}
 
 
console.log('script start')
   
new Promise( function( resolve ) {
 console.log('promise3')
 resolve();
} ).then( function() {
 console.log('promise4')
} )

setTimeout(function() {
  console.log('setTimeout')
}, 0)
 
async0(); 
   
new Promise( function( resolve ) {
 console.log('promise1')
 resolve();
} ).then( function() {
 console.log('promise2')
} )
 
console.log('script end')

结果

script start
promise3
async0 start
async1 start
async2
async3
async0 end
promise1
script end
promise4
async4
promise2
async1 end
async5
setTimeout
await从右向左执行

即先执行右边的表达式或函数,在阻塞下面的代码

这里注意一点,可能大家都知道await会让出线程,阻塞后面的代码,那么上面例子中, ‘async2’ 和 ‘script start’ 谁先打印呢?

是从左向右执行,一旦碰到await直接跳出, 阻塞async2()的执行?

还是从右向左,先执行async2后,发现有await关键字,于是让出线程,阻塞代码呢?

实践的结论是,从右向左的。先打印async2,后打印的script start

await 等到之后,做了一件什么事情?

那么右侧表达式的结果,就是await要等的东西。

等到之后,对于await来说,分2个情况

  • 不是promise对象
  • 是promise对象

如果不是 promise , await会阻塞后面的代码,先执行async外面的同步代码,同步代码执行完,再回到async内部,把这个非promise的东西,作为 await表达式的结果

如果它等到的是一个 promise 对象,await 也会暂停async后面的代码,先执行async外面的同步代码,等着 Promise 对象 fulfilled,然后把 resolve 的参数作为 await 表达式的运算结果。

注意点

!!!

一定要理解什么叫做fullfilled,是要执行完才叫fullfilled

先执行async外面的同步代码,同步代码执行完,要理解什么是async外面的同步代码,要能找的到

这道题的解法

首先整段代码放入宏任务中,

async function async0() {
  console.log('async0 start')
  async1()
  console.log('async0 end')
}
async function async1() {
  console.log('async1 start')
  await async2()
  console.log('async1 end')
  await async5()
} 
async function async2() {
  console.log('async2')
  await async3()
  await async4()

}
async function async3() {
  console.log('async3')
}
async function async4() {
  console.log('async4')
}
async function async5() {
  console.log('async5')
}

都是函数的定义,所以没有调用

执行

console.log('script start')
结果队列
script start

然后是promise

new Promise( function( resolve ) { console.log('promise3') resolve();} ).then( function() { console.log('promise4')} )

遇到promise是进入里面,执行resolve,然后把.then 的部分放入微任务

执行

 console.log('promise3') resolve();
结果队列
script startpromise3
微任务队列
1. console.log('promise4')

接下来是

setTimeout(function() {  console.log('setTimeout')}, 0)

这个是放入宏任务里,等微任务执行完才执行。

调用async0()

async function async0() {  console.log('async0 start')  async1()  console.log('async0 end')}

执行

 console.log('async0 start')
结果队列
script startpromise3async0 start

调用async1()

async1(); 

看到函数中

async function async1() {  console.log('async1 start')  await async2()  console.log('async1 end')  await async5()}

执行

console.log('async1 start')
结果队列
script startpromise3async0 startasync1 start

然后是这一行代码

await async2()

重点来了

上面说await从右向左执行,先执行async2,再看到await

所以我们直接到async2

async function async2() {  console.log('async2')  await async3()  await async4()}

执行

console.log('async2')
结果队列
script startpromise3async0 startasync1 startasync2

又遇到await

await async3()

到async3

async function async3() {  console.log('async3')}

执行

console.log('async3')
结果队列
script startpromise3async0 startasync1 startasync2async3

那我们现在看到async3执行完了,它就开始返回了

此时理解fullfilled,要返回了才加入微任务!!!

回到async2里

async function async2() {  console.log('async2')  await async3()  await async4()}

看到await,我们将下面的内容放入微任务

微任务队列
 1. console.log('promise4') 2. await async4()
此时我们应该回到哪里??

是回到

async function async1() {  console.log('async1 start')  await async2()  console.log('async1 end')  await async5()}

里面的

  await async2()

然后将下面的加入微任务??

还是回到宏任务??

答案是:回到宏任务

一直强调的是只有fullfilled才能看到await,然后阻塞,我们可以看到async2是没有执行完的,它里面还有

await async4()

这个事情是没做完,被我们放入了微任务里,所以还没有返回值。

所以我们回到宏任务。

那么有一个点来了

宏任务指哪里??

应该是最初调用的地方,没有await在的等待返回值的地方

async2没有执行完,那么async1肯定也没执行完,

我们就回到调用async1的地方

async function async0() {  console.log('async0 start')  async1()  console.log('async0 end')}

这里没有await,不需要等待返回值,可以直接进行下一步

我们返回的地点在

  async1()

那么假如

 我们将 async1() 改成 await async1()

我们该回到哪里??

显然, async1()没有返回值, async0(),也没有结束。

我们得回到调用 async0()的地方,执行async0()下面的代码

有兴趣可以在浏览器试试

回到正题

我们返回async1

执行下面的代码

 console.log('async0 end')
结果队列
script startpromise3async0 startasync1 startasync2async3async0 end

再回到最外面的

new Promise( function( resolve ) { console.log('promise1') resolve();} ).then( function() { console.log('promise2')} )

执行

 console.log('promise1') resolve();
结果队列
script startpromise3async0 startasync1 startasync2async3async0 endpromise1
微任务队列
 1. console.log('promise4') 2. await async4() 3. console.log('promise2')

最后的

console.log('script end')
结果队列
script startpromise3async0 startasync1 startasync2async3async0 endpromise1script end

第一次的宏队列结束,浏览器会自动查看微任务队列,有就执行,直到全部完成,才会再次执行宏队列。

我们看微队列

1. console.log('promise4')2. await async4()3. console.log('promise2')

执行

console.log('promise4')
结果队列
cript startpromise3async0 startasync1 startasync2async3async0 endpromise1script endpromise4

接下来

await async4()

进入async4()

async function async4() {  console.log('async4')}

执行

 console.log('async4')
结果队列
script startpromise3async0 startasync1 startasync2async3async0 endpromise1script endpromise4async4

这个函数结束,返回到

async function async2() {  console.log('async2')  await async3()  await async4()//返回到这里}

看到await,后面没有了,这个函数结束了

返回到

async function async1() {  console.log('async1 start')  await async2()//返回到这里  console.log('async1 end')  await async5()}

看到await,我们把后面的代码加入微任务队列

微任务队列
 3. console.log('promise2') 4. console.log('async1 end')     await async5()

然后就看下一个微任务

 console.log('promise2')

执行之后

结果队列
script startpromise3async0 startasync1 startasync2async3async0 endpromise1script endpromise4async4promise2

再看下一个

console.log('async1 end') 
结果队列
script startpromise3async0 startasync1 startasync2async3async0 endpromise1script endpromise4async4promise2async1 end

接下来

await async5()

进入其中,只有一行代码

console.log('async5') 
结果队列
script startpromise3async0 startasync1 startasync2async3async0 endpromise1script endpromise4async4promise2async1 endasync5

此时所有微任务执行完了

接下来执行下一个宏任务

setTimeout(function() {  console.log('setTimeout')}, 0)
结果队列
script startpromise3async0 startasync1 startasync2async3async0 endpromise1script endpromise4async4promise2async1 endasync5setTimeout
题目修改加上then
async function async2() {  console.log('async2')  await async3().then((res)=>{    console.log(res)  })  await async4()}async function async3() {  console.log('async3')  return 'ok'  // await async4()}

就改这两个

此时要注意的是,在进入async3里面后,

输出async3,我们回到async2

async function async2() {  console.log('async2')  await async3().//回到这里  then((res)=>{    console.log(res)  })  await async4()}

把then里面的内容加入微任务,然后就回到宏任务,下面的 await async4()不要加入到微任务里,因为

async3().then((res)=>{    console.log(res)})

还没有结束。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值