我一直在阅读John Resig的“JavaScript忍者的秘密”,它解释说JavaScript是单线程的。但是,我试过测试这个,我不知道该从这里带走什么:
// executing this in browser
(function () {
// throw something into event queue
setTimeout(function () {
alert("This will be called back after 1 second.");
}, 1000);
// arbitrary loop to take up some time
for (var i = 0; i < 10000; i += 1) {
console.log(i);
}
})();
也许我并不完全理解单线程意味着什么,但我认为在所有外部匿名函数完成之前,setTimeout回调不会执行。但是,在浏览器中运行它会显示回调函数在我仍然输出到控制台时被调用。对我来说,这似乎有两个线程,匿名函数的invokation占用1个线程,然后回调使用第二个线程。
有人可以帮助我混淆我吗?
答案 0 :(得分:11)
console.log()
在某些浏览器(如Chrome)中是一个奇怪的功能,并且本身不是同步的,因此您无法真正使用它来衡量单线程。您可能看到的是JS引擎执行所有console.log()
语句,然后setTimeout()
运行以显示警报,并且并行(在其他一些非javascript进程中)所有数据正在控制台中显示。
Javascript确实是单线程的。在您的示例中,setTimeout()
回调将在for
循环完成后才会执行。
你可以更好地说明这个:
(function () {
// throw something into event queue
setTimeout(function () {
alert("This will be called back after 1 second.");
}, 1000);
function now() {
return new Date().getTime();
}
var start = now();
// loop for 1.2 seconds
while (now() - start < 1200) {}
alert("Looping done");
})();
使用jsFiddle演示:http://jsfiddle.net/jfriend00/3sBTb/
答案 1 :(得分:4)
理解这是一个棘手的概念。投入事件听众之类的事情也会使图片更加混乱。
想到它的简单方法就好像你有一条传送带。你的正常函数调用都是均匀分布的,中间是空间。
异步事物(超时,触发事件等)填补了这些空白。每个普通调用之间没有无限大的空间,所以它适合它从这个队列中得到的东西,做一些正常的同步函数,用异步填充更多的空间等等。
效果似乎有点多线程(事实上,您可以使用异步调用导致排序的竞争条件)。在许多情况下,区别并不重要。但是,重要的是要记住这一点。
但是,当您尝试调试内容时,尤其是在使用Chrome console.log
之类的工具时,看起来事情会变得混乱,因为console.log本身是异步的(如果它是同步的,它会冻结您的脚本长期的功能)。
如果输出如下内容,您可以自己看到:
var input = document.createElement('input');
input.setAttribute('value', 0);
function inc() {
input.setAttribute('value', parseInt(input.getAttribute('value'))+1);
console.log(input);
if (parseInt(input.getAttribute('value')) < 100) {
setTimeout(inc, 10);
}
}
inc();
JSFiddle:http://jsfiddle.net/c2PnP/
这个脚本创建一个输入元素,然后每隔10毫秒,它会增加输入值,然后输出输入元素。它重复100次(直到值= 100)。
如果你看一下你的控制台,你会注意到一些值会被重复,这将不是一个平稳的进展。例如,在我刚刚进行的运行中,我看到5个输入值为“100”,缺少数字的间隙。这是因为console.log是异步运行的,只有在得到差距时才输出。
(注意:如果你有超快速的计算机,你可能需要将时间缩短到更小的值,比如1,和/或将迭代次数增加到更大的数量。)
答案 2 :(得分:3)
John Resig covered this well.总结:
“JavaScript一次只能执行一段代码(由于 它的单线程特性)...当发生异步事件时(如 鼠标单击,计时器触发或XMLHttpRequest完成它 排队等待稍后执行....在初始块之后 JavaScript完成执行浏览器后立即询问 问题:等待执行的是什么?然后浏览器选择一个 并立即执行。 [rest]将等到下一个 可能的时间,以便执行。“