理解JavaScript的单线程特性

时间:2014-01-29 21:57:23

标签: javascript multithreading events callback single-threaded

我一直在阅读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个线程,然后回调使用第二个线程。

有人可以帮助我混淆我吗?

3 个答案:

答案 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]将等到下一个   可能的时间,以便执行。“