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


当前回答

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

Javascript中不支持多线程,至少不是显式的,所以没有什么区别。

其他回答

是的,尽管Internet Explorer 9会在一个单独的线程上编译你的Javascript,为在主线程上执行做准备。但是,对于作为程序员的您来说,这并没有任何改变。

Javascript引擎必须是单线程,但Javascript运行时不需要是单线程。

Javascript引擎是什么?这是执行实际JS代码的解释器。引擎需要主机。它不能自己运行。主机是Javascript运行时。

例如,运行在Chrome浏览器中的V8引擎是单线程的。Chrome浏览器是一个运行时&它有其他进程/线程支持V8引擎。

你可以查看这篇文章,在那里有漂亮的解释。如果有帮助的话,别忘了回复并点赞:)

实际上,父窗口可以与拥有自己执行线程的子窗口或兄弟窗口或框架通信。

我已经尝试了@bobince的例子,做了轻微的修改:

<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

但如果你尝试在Opera或Firefox稳定的Windows上运行这个,并最小化/最大化屏幕上弹出的警告窗口,那么会有这样的东西:

click begin
resize
click end
result = 15, should be 20

我不想说,这是“多线程”,但一些代码在错误的时间执行,我没有预料到这一点,现在我有一个损坏的状态。 最好了解这种行为。

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

JavaScript通常被认为有一个对脚本可见的执行线程(*),因此当您的内联脚本、事件侦听器或超时输入时,您仍然完全处于控制状态,直到从块或函数的末尾返回。

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

然而,在现实中,这并不完全正确。

最常见的情况是即时事件。当你的代码做了一些导致它们的事情时,浏览器会立即触发它们:

var l= document.getElementById('log'); var i= document.getElementById('inp'); i.onblur= function() { l.value+= 'blur\n'; }; setTimeout(function() { l.value+= 'login in\n'; l.focus(); l.value+= '注销\n'; }, 100); i.focus(); <textarea id=“log” rows=“20” cols=“40”></textarea> <input id=“inp”>

结果登录,模糊,注销除了IE。这些事件并不仅仅因为您直接调用了focus()而触发,它们也可能因为您调用了alert(),或者打开了一个弹出窗口,或者其他任何移动焦点的操作而发生。

这也可能导致其他事件。例如,添加一个i.onchange监听器,在focus()调用取消聚焦之前在输入中输入一些东西,日志顺序是登录、更改、模糊、注销,除了在Opera中是登录、模糊、注销、更改,在IE中是(更难以解释的)登录、更改、注销、模糊。

类似地,在所有浏览器中,对提供click的元素调用click()会立即调用onclick处理程序(至少这是一致的!)

(我用的是…事件处理程序属性,但同样发生在addEventListener和attachEvent。)

在许多情况下,尽管您没有做任何事情来触发事件,但当您的代码被线程插入时,事件可能会被触发。一个例子:

var l= document.getElementById('log'); document.getElementById('act').onclick= function() { l.value+= 'alert in\n'; 警报(“警报! l.value+= 'alert out\n'; }; window.onresize= function() { l.value+= 'resize\n'; }; <textarea id=“log” rows=“20” cols=“40”></textarea> <按钮 id=“行动”>警报</button>

点击alert,你会得到一个模态对话框。在你终止对话之前不会再执行脚本,对吗?没有。调整主窗口的大小,你会在文本区得到警报进入,调整大小,警报退出。

你可能认为,当一个模态对话框打开时,调整窗口大小是不可能的,但事实并非如此:在Linux中,你可以随心所欲地调整窗口大小;在Windows上,这并不容易,但你可以通过将屏幕分辨率从较大的窗口调整为较小的窗口来实现,从而调整窗口的大小。

You might think, well, it's only resize (and probably a few more like scroll) that can fire when the user doesn't have active interaction with the browser because script is threaded. And for single windows you might be right. But that all goes to pot as soon as you're doing cross-window scripting. For all browsers other than Safari, which blocks all windows/tabs/frames when any one of them is busy, you can interact with a document from the code of another document, running in a separate thread of execution and causing any related event handlers to fire.

在脚本仍然线程化的情况下,你可以引起事件生成的地方:

when the modal popups (alert, confirm, prompt) are open, in all browsers but Opera; during showModalDialog on browsers that support it; the “A script on this page may be busy...” dialogue box, even if you choose to let the script continue to run, allows events like resize and blur to fire and be handled even whilst the script is in the middle of a busy-loop, except in Opera. a while ago for me, in IE with the Sun Java Plugin, calling any method on an applet could allow events to fire and script to be re-entered. This was always a timing-sensitive bug, and it's possible Sun have fixed it since (I certainly hope so). probably more. It's been a while since I tested this and browsers have gained complexity since.

总之,对于大多数用户来说,JavaScript在大多数情况下都具有严格的事件驱动的单线程执行。在现实中,它没有这样的东西。目前还不清楚其中有多少是简单的错误,有多少是故意设计的,但如果您正在编写复杂的应用程序,特别是跨窗口/框架脚本的应用程序,那么它很可能会以间歇性的、难以调试的方式咬你一口。

如果出现最糟糕的情况,您可以通过间接引导所有事件响应来解决并发问题。当事件传入时,将其放入队列中,然后在setInterval函数中按顺序处理队列。如果您正在编写一个用于复杂应用程序的框架,那么这样做可能是一个很好的举措。postMessage还有望在将来缓解跨文档脚本编写的痛苦。