5

在一次工作面试中,我很困惑地听到“javascript 可以无序地评估语句”。这在多大程度上是真实的?我可以想象一百种方法来明确地评估无序的语句——例如在分时操作系统中。但他似乎说如果我评估

console.log('a')
console.log('b')

Javascript 规范不要求输出是afirst then b。我可以想象,如果第一个语句的 IO 阻塞,如果语句在功能上是纯的,即没有副作用,那么评估器可能会尝试评估第二个语句,但副作用必须始终按顺序发生,对吗?当然,IO 是一大副作用。

符合规范的 Javascript 在多大程度上可以乱序评估?或者这是一个沟通不畅的案例?

4

4 回答 4

8

JavaScript 是单线程的(除了网络工作者)。时期。ECMA-262 语言规范版 5.1没有说明乱序执行。在您的简单示例中,这两个语句保证以相同的顺序执行。

此外,单个 JavaScript 代码块永远不会被任何其他代码块(例如事件处理程序)中断。这就是为什么长时间运行的代码块会导致 UI冻结

for(var i = 0; i < 1000000000; ++i) {
    console.log(i);
}

保证上面的代码块永远不会被中断或重新排序。只要循环正在运行,所有事件处理程序和超时都会等待单线程。当然,数字会以正确的顺序出现。

可能乱序执行的是异步超时:

setTimeout(function() {
    console.log('a');
}, 1);
setTimeout(function() {
    console.log('b');
}, 1);

在这里您可能希望a首先打印,但 JS 引擎可能会重新排序这些事件。毕竟,您安排这些调用在几乎相同的时间点执行。

于 2013-01-31T20:13:55.810 回答
2

明显误传。

这家伙可能指的是 JavaScript 提升。你可以在这里阅读更多关于它的信息:http: //www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting

此外,您可以在此处了解该语言的更多特性:http: //bonsaiden.github.com/JavaScript-Garden/

于 2013-01-31T20:15:04.980 回答
1

多半是对的。除了两个主要的例外(撇开明显的“定义一个函数,调用函数”,它有效地“回到”函数体):

1:吊装。var声明被提升,所以如果你写

alert(a);
var a = 123;

您得到undefined,而不是错误消息。这是因为它被吊到

var a;
alert(a);
a = 123;

同样,函数定义也被提升。如果你写:

foo(123);
function foo(num) {alert(num);}

它将起作用,因为该功能已被提升。但是,如果你写了这不起作用

foo(123);
foo = function(num) {alert(num);}

因为那是匿名函数的赋值,而不是函数定义。

2:异步函数。

初学者的一个常见错误是这样写:

var a = new XMLHttpRequest();
a.open("GET","sompage.php",true);
a.onreadystatechange = function() {
    if( a.readyState == 4 && a.status == 200) {
        myvar = "Done!";
    }
};
a.send();

alert(myvar);

他们希望警报说Done!,但相反,他们得到一个关于它未定义的莫名其妙的错误。这是因为myvar = "Done!"尚未运行,尽管它出现在脚本的较早部分。


另请参阅Computer Stupidities的这个轶事:

一位编程入门的学生曾经让我看一下他的程序,并弄清楚为什么它总是因为简单的计算而产生零。我看了看程序,很明显:

begin
 readln("Number of Apples", apples);
 readln("Number of Carrots", carrots);
 readln("Price for 1 Apple", a_price);
 readln("Price for 1 Carrot", c_price);
 writeln("Total for Apples", a_total);
 writeln("Total for Carrots", c_total);
 writeln("Total", total);
 total := a_total + c_total;
 a_total := apples * a_price;
 c_total := carrots + c_price;
end;
  • 我:“嗯,你的程序不能在计算之前打印出正确的结果。”
  • 他:“嗯?正确的解决方案是合乎逻辑的,计算机应该以正确的方式重新排列指令。”
于 2013-01-31T20:18:56.790 回答
0

我认为他们试图让你站在错误的立场上。Javascript是顺序的。否则,您计算值的函数将无法运行。可能是真的,它console.log激活了一个Async task,这意味着它可以以不同的顺序执行。就像一个Ajax电话,一个Webworker,一个timeout或一个interval

如果您执行以下操作,它将导致 B 比 A,这不是顺序代码,因为在代码中。A 为 B 来,但 B 先被执行。

setTimeout(function(){
    console.log("A")
}, 5);
console.log("B");
于 2013-01-31T20:13:09.397 回答