setTimeout设置延迟为0时与setImmediate的区别

394 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情

前情提要

在上篇文章研究js的事件循环(Event Loop)的时候发现了一个问题。我在代码的一级列里同时写了setTimeout和setImmediate。其中setTimeout的延迟时间设置为了0。然后第一次运行setTimeout先执行,setImmediate后执行。但是当我继续重复几次之后,发现他们俩居然会偶尔的相互交替先执行。一会setTimeout先执行,一会setImmediate先执行。好奇怪呀。

展示

示例一

  • 代码

    setTimeout(() => {
        console.log(1)
    }, 0)
    setImmediate(() => {
        console.log(2)
    })
    
  • 执行结果

    WX20220527-160433@2x.png

  • 总结:从多次执行结果上看,他们俩确实会出现一会他前一会他后的问题。

  • 原因: ?

示例二

  • 代码

    function fn() {
        setTimeout(() => {
            console.log(1);
        }, 0);
        setImmediate(() => {
            console.log(2);
        });
    }
    fn();
    
  • 执行结果

    WX20220527-160851@2x.png

  • 总结:从代码执行结果上来看,大多数情况下在方法里是setImmediate先执行,setTimeout延迟为0后执行。但偶尔也会反过来。

  • 原因:?

浏览器环境

我将上述的代码又放到了浏览器里去执行。执行了很多次之后发现打印结果始终都是先打印2后打印1。上述代码是在node环境中执行的。也就是说这种不稳定的情况只出现在node环境中,在浏览器环境中并不存在。这个结论可以让我们放心大胆的去写前端涉及这两个逻辑了。

打破砂锅问到底:为什么node环境会出现这个问题?

  • 在查阅了很多资料后发现问题可能出现在了node的事件循环上。
  • 事实上浏览器的事件循环与node的事件循环并不一样。也因此产生了如此的差异
  • 具体原因是在node找那个基本上做不到0秒,其处理逻辑最少也需要1毫秒的时间。此时进入事件循环后,如果没有到1毫秒,那么就会跳过,进而执行下面的。如果到了就会执行上面的。所以出现了不稳定的情况。
  • 上一句的解释可能会差强人意些,有兴趣的xdm可以着重的了解下node的事件循环。待我有时间了解清楚node事件循环后再来详细解释。