为什么 setTimeout 是同步执行的?

XXI*_*XIV 0 javascript event-loop task-queue

setTimeout下面是同步代码之后执行的例子

console.log('hello');
setTimeout(() => console.log('timeout'), 0);
console.log('end');
Run Code Online (Sandbox Code Playgroud)

控制台输出:hello end timeout

异步:

function asyncForEach(array, callBack) {
    array.forEach(x => setTimeout(callBack(x), 0));
}
asyncForEach([1,2,3,4], (i) => console.log(i)); 
console.log('end');
Run Code Online (Sandbox Code Playgroud)

控制台输出:

1
2
3
4
end
Run Code Online (Sandbox Code Playgroud)

同步:

[1,2,3,4].forEach(x => console.log(x));
console.log('end');
Run Code Online (Sandbox Code Playgroud)

控制台输出:

1
2
3
4
end
Run Code Online (Sandbox Code Playgroud)

我试图更好地理解event looptask queue,并且在观看了一个很好的推荐视频(https://www.youtube.com/watch?v=8aGhZQkoFbQ)后,遇到了以下半声明:“回调可以是同步和异步的”。演讲者继续演示同步方式如何最终不会通过task queue,因此不会通过event loop,因此所有内容都保留在stack. 但是,异步方式会导致task queue用 的最终返回填充setTimeout callback,这将使任何同步的下面代码可执行,因为event loop必须等待一个空stack来插入返回的callback.

运行上面的代码时(我从他那里偷来的东西也编辑过,所以这可能是我的错误添加),异步方式产生与同步方式相同的结果。

有人可以帮助解释为什么异步方式不作为第一个setTimeout示例和/或提供解释如何不将常规回调(例如数组帮助程序方法)插入task queue因此从未被event loop?

Sha*_*ger 5

您的“异步方式”不是异步的,因为您调用了该函数并将其返回值传递给setTimeout

function asyncForEach(array, callBack) {
    array.forEach(x => setTimeout(callBack(x), 0)); // <-- callBack(x) calls callBack immediately
}
asyncForEach([1,2,3,4], (i) => console.log(i)); 
console.log('end');
Run Code Online (Sandbox Code Playgroud)

如果您希望延迟,请创建一个传递给setTimeout它可以稍后调用的函数:

function asyncForEach(array, callBack) {
    array.forEach(x => setTimeout(() => callBack(x), 0)); // <-- Makes closure that calls callBack(x) later
}
asyncForEach([1,2,3,4], (i) => console.log(i)); 
console.log('end');
Run Code Online (Sandbox Code Playgroud)