【问题标题】:Call Stack while using setTimeout()使用 setTimeout() 时调用 Stack
【发布时间】:2018-05-03 14:50:45
【问题描述】:

我对 setTimeout 有点困惑。我想确认以下代码的输出是否总是:

inside abc
inside sample

代码:

function abc() {
    xyz();

    // interactions and modifications in DOM 
    $("#id1").append("something");
    $("#id2").val("set something");
    $("#id3").after("create some dynamic element");
    // 10 to 20 interaction more...

    console.log('inside abc');
}

function xyz() {
    setTimeout(function() {
        sample();
    },0);  
}

function sample() {
    console.log('inside sample')
}

如果有人可以用调用堆栈解释整个流程,那就太好了。

【问题讨论】:

  • 如果人们(和我一样)在回调运行时看到 setTimeout 和“堆栈上”的其他帧而感到困惑,请注意某些浏览器(例如 Chrome)会尝试通过显示 @ 来帮助调试987654321@。视觉上不是很清楚,但“setTimeout (async)”表示它实际上不在堆栈上。

标签: javascript


【解决方案1】:

是的,它总会有那个输出。

setTimeout 中的回调在执行上下文明确之前不会被调用 - 即当前执行的代码序列已经完成。

这意味着即使你这样做了

setTimeout(function () { console.log("1 second!"); }, 1000);

var start = +new Date();
while ((+new Date()) - start < 5000) {}

1 second! 不会在 5 秒后被记录。

【讨论】:

  • 还有一件事...... DOM 交互是同步的还是异步的?
  • @ShekharJoshi "哪个代码?"所有代码除了调用sample()。我的意思是 Javascript 引擎逐行遍历代码,一次一个,直到没有更多行可以执行。只有当没有更多的行可以执行,并且控制返回到包含环境时,setTimeout 回调才能运行。对 DOM 的修改是同步的。 DOM 事件是异步的。
【解决方案2】:

setTimeout() 将在完成当前执行块后异步运行。所以输出应该总是相同的:

inside abc
inside sample

Javascript 在内部管理所有异步任务的事件队列。每次它在完成当前执行块后检查它的异步队列。

【讨论】:

    【解决方案3】:

    是的,控制台输出将始终相同。 setTimeout 的回调函数在调用它的上下文被清除后异步执行。调用 setTimeout 时,它会将其回调函数放在堆栈上并返回到当前执行上下文。完成后(在您的示例中,当 abc 完全执行时),将执行回调函数,在您的示例中基本上立即调用 sample。所以你的代码输出永远不会不同。

    如果您在调用 xyz 之前在 abc 中的某处放置了较长的 setTimeout 函数,则可以看出 setTimeout 的回调本身是异步执行的:

    function abc() {
        setTimeout(function(){
            console.log('wait')
        },1000);
        xyz();
        console.log('inside abc');
    }
    function xyz() {
        setTimeout(function(){
            sample();
        } ,0);  
    }
    function sample() {
        console.log('inside sample');
    }
    abc();    
    

    ...您的控制台将记录:

    inside abc
    inside sample
    wait
    

    要在较长的超时完成之前保持样本的执行,您需要将 setTimeout 调用样本放入较长的 setTimeout。

    如果 setTimeout 的回调一直表现不同,很可能是由于意外传递了函数调用而不是函数指针,如下所示:

    setTimeout(sample(),0);
    

    而不是

    setTimeout(sample,0)
    

    另外,如果您不知道(或其他人),您可以添加

    debugger;
    

    在您的 Javascript 代码中的任何点,然后运行代码以使用开发工具查看该点的调用堆栈(在 Chrome 中,它位于右侧面板中的“源”下)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-26
      • 2021-02-23
      • 2013-08-21
      • 1970-01-01
      • 2022-07-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多