为什么setTimeout同步动作?

时间:2019-06-30 00:53:03

标签: javascript task-queue event-loop

setTimeout在下面的同步代码之后被执行的示例

console.log('hello');
setTimeout(() => console.log('timeout'), 0);
console.log('end');

控制台输出:     你好     结束     超时

异步:

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

控制台输出:

1
2
3
4
end

同步:

[1,2,3,4].forEach(x => console.log(x));
console.log('end');

控制台输出:

1
2
3
4
end

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

运行上面的代码时(我从他那里偷走了东西,还进行了编辑,因此对我而言可能是错误的添加),异步方式产生的结果与同步方式相同。

有人可以帮助解释为什么异步方式不作为第一个setTimeout示例的原因和/或提供有关如何不将常规回调(例如数组帮助器方法)插入{{1}的解释。 }因此从未被task queue弄乱吗?

2 个答案:

答案 0 :(得分:4)

您的“异步方式”不是异步的,因为您调用了该函数并将其返回值传递给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');

如果您希望它延迟,则将一个函数传递给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');

答案 1 :(得分:2)

您的asyncForEach函数中存在错误。您正在立即调用callBack(x),然后将该函数(undefined)的结果传递给setTimeout