javascript SetInterval /异步等待异常

k3fezbri  于 2022-11-20  发布在  Java
关注(0)|答案(1)|浏览(307)

考虑下面的两个函数,都是异步的,一个是占用大量时间的繁重工作负载,另一个是通过设置超时等待精确秒数的等待函数。

async function Brutal_Workload()
{
 for(var x = 0; x< 1000 * 1000 * 1000; x++)
 {
 }
}

async function Time_Wait(seconds)
{
 var promise = new Promise((resolve, reject) =>
 {
  var msecs = Math.floor(seconds  * 1000);
     
  var timer = 
  setTimeout(
  function()
  {
   clearTimeout(timer);
   
   resolve();     
  }, 
  msecs);
  
 });
 
 return promise;
}

现在,让我们调用setInterval循环中的第一个函数

setInterval(
async function()
{
 await Brutal_Workload();
    
 console.log("BLIP");
}, 1000 / 30);

全部符合预期:尽管间隔以每秒30次调用的速度运行,但我每秒只得到1个blip,因为Brutal_Workload阻塞了它。
但是当我使用另一个功能时...

setInterval(
async function()
{
 await Time_Wait(1);
    
 console.log("BLIP");
}, 1000 / 30);

我每秒得到30个BLIP。Time_Wait函数在setInterval之外工作正常,但在这里似乎不工作。
知道是什么原因导致这种行为吗?

cbeh67ev

cbeh67ev1#

好吧,与其继续在评论中来回,我只是要张贴这作为一个答案。
Javascript是单线程的 * 和 * 并发的。我知道你知道这一点,但你似乎没有意识到其中的含义。在你的第一个函数中,你只偶尔看到一个console.log,因为你的“残酷的工作负载”阻塞了唯一的执行线程,直到它完成,这意味着无论你传递给setInterval的数字是多少,不仅没有其他调用在运行,下一项工作 * 甚至没有 * 排队 * 运行,因为您的繁重工作负载阻塞了 * 唯一的 * 执行线程 *。
了解,运行时环境的setInterval运行在相同的因此,虽然工作负载很大,但setInterval本身,更不用说你传递给它的函数,根本没有运行 *。使用async并将繁重的工作负载 Package 在Promise中,就我们这里的讨论而言,基本上没有任何区别,因为繁重的工作负载占主导地位。
这就解释了第一个例子,到目前为止一切顺利,继续第二个。
与第一个示例不同,在第二个示例中,没有长时间运行的代码块来束缚执行线程,因此您对setInterval的回调运行,忠实地注册了一个要在一秒钟内运行的东西,并 * 产生了对执行线程的控制 *。第一个例子也没有这里Promise和async/await实际上 * 确实 * 启用了并发,而在第一个示例中它无法做到这一点,因为繁重的工作负载占据了线程。因此,在几分之一秒内,您对setInterval的回调再次运行,并尽职尽责地排队等待一秒后运行另一个对象,以此类推。
因此,在大约1秒后,第一个排队的日志发生,然后在几分之一秒后,第二个,依此类推。这不会发生在第一个例子中,因为虽然你告诉setInterval运行30倍/秒残酷的工作负载意味着setInterval * 本身 * 不能运行,甚至 * 排队 * 您的回调运行。

相关问题