JavaScript保证是单线程的吗?

JavaScript保证是单线程的吗?,javascript,concurrency,Javascript,Concurrency,众所周知,JavaScript在所有现代浏览器实现中都是单线程的,但这是在任何标准中指定的,还是仅仅是传统?假设JavaScript始终是单线程的,这是完全安全的吗?是的,尽管在使用任何异步API(如setInterval和xmlhttp回调)时,您仍然会遇到并发编程的一些问题(主要是竞争条件)。我会说是的,因为几乎所有的API都存在(至少所有非平凡的API)如果浏览器的javascript引擎异步运行,javascript代码将中断 此外,在基本javascript中引入多线程(多线程java

众所周知,JavaScript在所有现代浏览器实现中都是单线程的,但这是在任何标准中指定的,还是仅仅是传统?假设JavaScript始终是单线程的,这是完全安全的吗?

是的,尽管在使用任何异步API(如setInterval和xmlhttp回调)时,您仍然会遇到并发编程的一些问题(主要是竞争条件)。

我会说是的,因为几乎所有的API都存在(至少所有非平凡的API)如果浏览器的javascript引擎异步运行,javascript代码将中断

此外,在基本javascript中引入多线程(多线程javascript代码的显式标准化API)几乎毫无意义


其他评论者注意:即使
setTimeout/setInterval
、HTTP请求onload事件(XHR)和UI事件(单击、聚焦等)都是如此。)提供多线程性的粗略印象-它们仍然沿着单个时间线执行-一次执行一个-因此,即使我们事先不知道它们的执行顺序,也不必担心在执行事件处理程序、定时函数或XHR回调期间外部条件的变化。)

,Chrome是多进程的,我认为每个进程都处理自己的Javascript代码,但就代码所知,它是“单线程的”


Javascript中没有对多线程的任何支持,至少没有明确的支持,因此没有任何区别。

是的,尽管Internet Explorer 9将在单独的线程上编译Javascript,以准备在主线程上执行。但是,对于程序员来说,这不会改变任何事情。

JavaScript/ECMAScript被设计为生活在主机环境中。也就是说,除非宿主环境决定解析和执行给定的脚本,并提供让JavaScript真正有用的环境对象(例如浏览器中的DOM),否则JavaScript实际上不会做任何事情


我认为给定的函数或脚本块将逐行执行,这对于JavaScript是有保证的。但是,主机环境可能可以同时执行多个脚本。或者,主机环境可以始终提供提供多线程的对象
setTimeout
setInterval
是主机环境的示例,或者至少是伪示例,它们提供了一种实现某种并发性的方法(即使不完全是并发性)。

这是一个好问题。我想说“是的”。我不能

JavaScript通常被认为有一个对脚本(*)可见的执行线程,因此当输入内联脚本、事件侦听器或超时时,您将保持完全控制,直到您从块或函数结束返回

(*:忽略浏览器是否真的使用一个OS线程实现其JS引擎,或者WebWorkers是否引入了其他有限的执行线程。)

然而,在现实中,这并不完全是真的,以卑鄙的方式

最常见的情况是即时事件。当您的代码导致这些错误时,浏览器会立即触发这些错误:

var l=document.getElementById('log');
var i=document.getElementById('inp');
i、 onblur=函数(){
l、 值+='blur\n';
};
setTimeout(函数(){
l、 值+='登录\n';
l、 焦点();
l、 值+='注销\n';
}, 100);
i、 焦点()


实际上,父窗口可以与运行自己的执行线程的子窗口或同级窗口或帧进行通信。

尝试将两个setTimeout函数嵌套在一起,它们将表现为多线程(即,外部计时器在执行其功能之前不会等待内部计时器完成)。

我要反对这里的人群,但请容忍我。单个JS脚本旨在有效地实现单线程,但这并不意味着不能对其进行不同的解释

假设您有以下代码

var list = [];
for (var i = 0; i < 10000; i++) {
  list[i] = i * i;
}
var list=[];
对于(变量i=0;i<10000;i++){
列表[i]=i*i;
}
写这篇文章的目的是希望在循环结束时,列表必须有10000个索引平方的条目,但是VM可能会注意到循环的每个迭代都不会影响另一个,并使用两个线程重新解释

第一根线

for (var i = 0; i < 5000; i++) {
  list[i] = i * i;
}
for(变量i=0;i<5000;i++){
列表[i]=i*i;
}
第二线

for (var i = 5000; i < 10000; i++) {
  list[i] = i * i;
}
for(变量i=5000;i<10000;i++){
列表[i]=i*i;
}
我在这里进行了简化,因为JS数组比哑内存块更复杂,但是如果这两个脚本能够以线程安全的方式向数组中添加条目,那么当这两个脚本都完成执行时,它将获得与单线程版本相同的结果

虽然我不知道有哪种虚拟机检测到像这样的可并行化代码,但它似乎可能会在未来的JIT虚拟机中出现,因为它在某些情况下可以提供更高的速度

进一步考虑这个概念,可以对代码进行注释,让VM知道如何转换为多线程代码

// like "use strict" this enables certain features on compatible VMs.
"use parallel";

var list = [];

// This string, which has no effect on incompatible VMs, enables threading on
// this loop.
"parallel for";
for (var i = 0; i < 10000; i++) {
  list[i] = i * i;
}
//与“使用严格”类似,这可以在兼容的虚拟机上启用某些功能。
“使用并行”;
var列表=[];
//此字符串对不兼容的虚拟机没有影响,在虚拟机上启用线程
//这个循环。
“平行于”;
对于(变量i=0;i<10000;i++){
列表[i]=i*i;
}

由于网络工作者开始使用Javascript,这不太可能。。。更丑陋的系统将永远存在,但我认为可以肯定地说Javascript是传统的单线程系统。

@Bobince提供了一个非常不透明的答案

根据MárÖrlygsson的回答,Javascript始终是单线程的,因为一个简单的事实:Javascript中的所有内容都是沿着单个时间线执行的

这是严格的定义
<html>
<head>
    <title>Test</title>
</head>
<body>
    <textarea id="log" rows="20" cols="40"></textarea>
    <br />
    <button id="act">Run</button>
    <script type="text/javascript">
        let l= document.getElementById('log');
        let b = document.getElementById('act');
        let s = 0;

        b.addEventListener('click', function() {
            l.value += 'click begin\n';

            s = 10;
            let s2 = s;

            alert('alert!');

            s = s + s2;

            l.value += 'click end\n';
            l.value += `result = ${s}, should be ${s2 + s2}\n`;
            l.value += '----------\n';
        });

        window.addEventListener('resize', function() {
            if (s === 10) {
                s = 5;
            }

            l.value+= 'resize\n';
        });
    </script>
</body>
</html>
click begin
click end
result = 20, should be 20
click begin
resize
click end
result = 15, should be 20