JavaScript是否保证是单线程的? [英] Is JavaScript guaranteed to be single-threaded?

查看:220
本文介绍了JavaScript是否保证是单线程的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

JavaScript在所有现代浏览器实现中都是单线程的,但是是在任何标准中指定的,还是仅仅是传统的?是否完全可以假设JavaScript总是单线程的?

JavaScript is known to be single-threaded in all modern browser implementations, but is that specified in any standard or is it just by tradition? Is it totally safe to assume that JavaScript is always single-threaded?

推荐答案

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

That's a good question. I'd love to say "yes". I can't.

JavaScript通常被认为有一个单独的脚本执行线程(*),所以当你的内联脚本,事件监听器或超时是

JavaScript is usually considered to have a single thread of execution visible to scripts(*), so that when your inline script, event listener or timeout is entered, you remain completely in control until you return from the end of your block or function.

(*:忽略了浏览器是否真正实现他们的JS引擎的问题OS-thread或者其他有限的执行线程是否由WebWorkers引入。)

(*: ignoring the question of whether browsers really implement their JS engines using one OS-thread, or whether other limited threads-of-execution are introduced by WebWorkers.)

但是,实际上这个不是真的

最常见的情况是即时事件。当您的代码执行某些操作时,浏览器会立即触发它们,导致他们:

The most common case is immediate events. Browsers will fire these right away when your code does something to cause them:

<textarea id="log" rows="20" cols="40"></textarea>
<input id="inp">
<script type="text/javascript">
    var l= document.getElementById('log');
    var i= document.getElementById('inp');
    i.onblur= function() {
        l.value+= 'blur\n';
    };
    setTimeout(function() {
        l.value+= 'log in\n';
        l.focus();
        l.value+= 'log out\n';
    }, 100);
    i.focus();
</script>

结果在登录,模糊,注销除了IE之外的所有。这些事件不只是触发,因为你直接调用 focus(),他们可能发生,因为你调用 alert() ,或打开一个弹出式窗口,或任何其他移动焦点的东西。

Results in log in, blur, log out on all except IE. These events don't just fire because you called focus() directly, they could happen because you called alert(), or opened a pop-up window, or anything else that moves the focus.

这也可能导致其他事件。例如,添加一个 i.onchange 监听器,并在 focus()调用解除聚焦之前在输入中键入内容,日志顺序为登录,更改,模糊,注销,除了在Opera中它登录,模糊,注销,更改和IE其中(更不明显)登录,更改,注销,模糊

This can also result in other events. For example add an i.onchange listener and type something in the input before the focus() call unfocuses it, and the log order is log in, change, blur, log out, except in Opera where it's log in, blur, log out, change and IE where it's (even less explicably) log in, change, log out, blur.

同样在一个元素上调用 click(),它会立即在所有浏览器中调用 onclick 是一致的!)。

Similarly calling click() on an element that provides it calls the onclick handler immediately in all browsers (at least this is consistent!).

(我在这里使用直接 on ... addEventListener attachEvent 也会发生同样的情况。)

(I'm using the direct on... event handler properties here, but the same happens with addEventListener and attachEvent.)

还有一些情况下,事件可以触发,而你的代码进入,尽管你已经做了没有挑起它。示例:

There's also a bunch of circumstances in which events can fire whilst your code is threaded in, despite you having done nothing to provoke it. An example:

<textarea id="log" rows="20" cols="40"></textarea>
<button id="act">alert</button>
<script type="text/javascript">
    var l= document.getElementById('log');
    document.getElementById('act').onclick= function() {
        l.value+= 'alert in\n';
        alert('alert!');
        l.value+= 'alert out\n';
    };
    window.onresize= function() {
        l.value+= 'resize\n';
    };
</script>

点击 alert 模态对话框。没有更多的脚本执行,直到你关闭对话,是的?不。调整主窗口大小,您将在textarea中获得提醒,调整大小,提示

Hit alert and you'll get a modal dialogue box. No more script executes until you dismiss that dialogue, yes? Nope. Resize the main window and you will get alert in, resize, alert out in the textarea.

在模态对话框启动时,不可能调整窗口大小,但不是这样:在Linux中,您可以根据需要调整窗口大小;在Windows上这不是那么容易,但你可以通过将屏幕分辨率从较大的更改为较小的窗口不适合,从而导致其调整大小。

You might think it's impossible to resize a window whilst a modal dialogue box is up, but not so: in Linux, you can resize the window as much as you like; on Windows it's not so easy, but you can do it by changing the screen resolution from a larger to a smaller one where the window doesn't fit, causing it to get resized.

你可能会想,只有 resize (可能还有一些像 scroll )当用户没有与浏览器的主动交互,因为脚本是线程的。而对于单窗口,你可能是对的。但是,一旦你做跨窗口脚本,所有这一切都会发生。对于Safari以外的所有浏览器,当其中任何一个忙时阻止所有窗口/标签/框架,您可以与来自另一个文档的代码的文档进行交互,在另一个执行线程中运行,并导致任何相关的事件处理程序火。

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.

可以引起生成事件的地方可以在脚本仍在线程时生成:

Places where events that you can cause to be generated can be raised whilst script is still threaded:

    ,<$ c $>在 showModalDialog 期间,在

$ c>在支持它的浏览器上;

during showModalDialog on browsers that support it;

此页面上的脚本可能正忙...对话框,即使您选择让脚本继续运行,允许像调整大小和模糊等事件触发,即使在脚本处于繁忙循环的中间时也可以处理,除了Opera。

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.

一段时间以前,对于我来说,在IE中使用Sun Java插件,调用applet上的任何方法都可以允许触发事件并重新输入脚本。这总是一个时间敏感的bug,它可能是太阳已经固定它(我当然希望如此)。

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.

,大多数时候,有一个严格的事件驱动的单线程执行。在现实中,它没有这样的事情。它不清楚这是多少是一个错误和多少有意设计,但如果你编写复杂的应用程序,特别是跨窗口/框架脚本,有一切可能会咬你 - 和间歇,难以调试的方式。

In summary, JavaScript appears to most users, most of the time, to have a strict event-driven single thread of execution. In reality, it has no such thing. It is not clear how much of this is simply a bug and how much deliberate design, but if you're writing complex applications, especially cross-window/frame-scripting ones, there is every chance it could bite you — and in intermittent, hard-to-debug ways.

如果最糟糕的情况是最糟糕的,你可以通过间接所有事件响应解决并发问题。当一个事件进来时,将其放入一个队列中,并在稍后的 setInterval 函数中处理队列。如果你正在编写一个框架,你打算被复杂的应用程序使用,这样做可能是一个好的举动。 postMessage 也将有助于缓解未来跨文档脚本的痛苦。

If the worst comes to the worst, you can solve concurrency problems by indirecting all event responses. When an event comes in, drop it in a queue and deal with the queue in order later, in a setInterval function. If you are writing a framework that you intend to be used by complex applications, doing this could be a good move. postMessage will also hopefully soothe the pain of cross-document scripting in the future.

这篇关于JavaScript是否保证是单线程的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆