定时器也是异步,为什么await不等它?

2022-03-10  本文已影响0人  子绎

先说结论:await实际上等待了定时器,只是因为定时器执行立马返回了随机数,所以await认为此条异步已结束,可以放行。

这个问题起源于我在看关于promise和await相关的文章。我发现大家都很喜欢一上来就拿定时器举例子,在定时器上包裹一个promise,然后利用promise来通知定时器是否结束。就像下面这样

return new Promise(res){
   setTimeouet(()=>{
    console.log('我执行结束了');
    res()
    },3000)   
  }

这引起了我的疑惑,定时器自己本身就是一个异步,为何还需要额外用一个promise来包装?
要弄懂这个问题,首先看我们平时怎么使用定时器:

const timeId = setTimeout(()=>{},3000);
clearTimeout(timeId)

以上的例子中,我们一开始用一个变量接收这个定时器的变量,然后接下来我们随时可以利用清理定时器函数清理这个变量。也就是清理了对应的定时器
换句话来说,这个变量在js读到定时器这行代码时,会优先返回一个随机变量,我们用timeId接收,用于将来清理定时器,而这个动作是同步的。此时定时器还并未开始倒计时。 也就是说,定时器开始倒计时定时器返回随机变量是两件事情。

---------------------------------------------------分割线------------------------------------------------------------------------------------

我们再次将重心放在await上,我们都知道await是在等待一个异步结束,但事情好像并没有那么简单。
实际上,await等待的是一个返回值,只要await接收到了返回值,await就会放行继续往下执行其他代码。

我们看这样一行简要代码

function test(){ return 30 }
await test()
console.log('你好')

以上这种写法也是没有任何问题的,因为await等待的是一个返回值,所以当test函数一执行,立马就会返回数字30,await能够第一时间拿到返回值,也能够第一时间放行,继续往下执行console.log("你好")
理论上:await不会在乎等待的是异步还是同步,它只在乎你什么时候返回结果给它,允许它继续往下走。

-----------------------------------------------分割线------------------------------------------------------------------------------------------------------

我们将重心放在promise上,promise的功能,就是包裹一段异步代码,并且通过回调函数通知异步是否执行完毕。 如下代码:

 function test(){
   return new Promise((res,rej)=>{
      setTimeout(()=>{
          res()
     },3000)
   })
}
await test();
console.log("你好")

以上的代码片段,我们可以简单理解为:定时器是否结束这个状态,由promise来通知外界。

你可能会疑惑,test第一时间将promise返回了,await不是已经接收到值了吗?为什么它还会等待promise?
其实这个就是promise的作用了,例子中,虽然我们第一时间return返回了promise给外界的await。但是由于promise自身的机制,await实际上接收到的是promise的实例对象,await又在等待promise这个实例对象将状态pendding执行到fulfilled状态,也就是我们定时器内部开发者自己手动调用的res(),来控制promise是否执行完成

也就是promise的完成状态 是由开发者控制的,我们只需要将promise对象return出去给await,由await实时监听你的内部什么时候调用res()完成,await才会继续往下执行。

总结:

我们回到第一个问题,定时器也是异步,为什么await不等它?
实际上await已经等待了定时器,只不过定时器第一时间返回了一个随机数给await。
其实只要有返回值,await都会放行。
定时器自身就是一个函数,在定时器内部return是return不出去的,它只会return定时器这一层。由于return的函数层数限制(1层),所以需要promise这样不管多少层都可以随时告知外界执行状态的神器。

另外:await是generate的语法糖,generate的特质就是允许开发者手动控制执行的时机,当await在等待时,会阻塞后面的代码,也就实现了将一个异步的结果处理成同步。

上一篇 下一篇

猜你喜欢

热点阅读