6

Я читал «Секреты JavaScript-ниндзя» Джона Ресига и объясняет, что 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 обратного вызова не будет выполняться до тех пор, пока не будет завершена вся внешняя анонимная функция. Однако запуск этого в браузере показывает, что функция обратного вызова вызывается, пока я все еще выводится на консоль. Для меня это похоже на 2 потока с invokeation анонимной функции, занимающих 1 поток, а затем обратный вызов с использованием 2-го потока.

Может кто-нибудь помочь мне не смутить?

+0

'console.log' является асинхронным, по крайней мере, через IE, Firefox, Chrome. Подробнее: http://stackoverflow.com/questions/4057440/is-chromes-javascript-console-lazy-about-evaluating-arrays. Асинхронность не предполагает многопоточность. – Noseratio

ответ

11

console.log()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/

+0

Спасибо @ jfriend00! Я не понимал, что console.log будет странным. Ваш код подчеркивает поведение, которое я ожидал увидеть! – wmock

3

John Resig covered this well. Сведение:

«JavaScript может только когда-либо выполнить один фрагмент кода, в то время (из-за его однопоточных природы) ... когда асинхронное событие происходит (как щелчок мыши , срабатывание таймера или заполнение XMLHttpRequest), он ставится в очередь для выполнения позже .... После начального блока JavaScript заканчивает выполнение браузера сразу же спрашивает вопрос : что ждет выполнения? Браузер затем выбирает один и выполняет его немедленно. [rest] будет ждать следующее возможное время, чтобы выполнить ».

4

Это немного каверзный концепции, чтобы понять. Бросание в вещи, такие как слушатели событий, еще больше мутирует картину.

Простой способ думать об этом как будто у вас есть конвейер. У вас есть обычные функции, все равномерно распределенные между собой.

Вещи, которые являются асинхронными вещами (таймауты, срабатывающие события и т. Д.), Заполняют эти точки. Между каждым из этих обычных вызовов нет бесконечного количества места, поэтому он подходит для того, что он может от этой очереди, выполняет немного больше обычных синхронизированных функций, заполняет еще немного места асинхронным и т. Д.

аффект кажется несколько многопоточным (и действительно, вы можете вызвать гоночные условия сорта с асинхронными вызовами). Во многих случаях различие не имеет значения. Однако важно помнить об этом.

Однако, когда вы пытаетесь отлаживать вещи, особенно при использовании таких инструментов, как: console.log, Chrome может выглядеть так, как будто вещи скремблируются, потому что сам 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, и/или увеличить количество итераций до большего числа).

+0

Спасибо @samanime! Аналогия конвейерной ленты действительно помогает мне понять это лучше! – wmock