program story

JavaScript는 단일 스레드가 보장됩니까?

inputbox 2020. 10. 3. 10:35
반응형

JavaScript는 단일 스레드가 보장됩니까?


JavaScript는 모든 최신 브라우저 구현에서 단일 스레드로 알려져 있지만 표준에 지정되어 있습니까 아니면 전통에 의해서만 지정됩니까? JavaScript가 항상 단일 스레드라고 가정하는 것이 완전히 안전합니까?


그건 좋은 질문이야. “예”라고 말하고 싶습니다. 난 못해.

JavaScript는 일반적으로 scripts (*)에 단일 실행 스레드가 표시되는 것으로 간주되므로 인라인 스크립트, 이벤트 리스너 또는 시간 제한이 입력되면 블록 또는 함수의 끝에서 돌아올 때까지 완전히 제어 할 수 있습니다.

(* : 브라우저가 실제로 하나의 OS 스레드를 사용하여 JS 엔진을 구현하는지 여부 또는 다른 제한된 실행 스레드가 WebWorkers에 의해 도입되는지 여부에 대한 질문을 무시합니다.)

그러나 실제로 이것은 비열한 방식으로 사실이 아닙니다 .

가장 일반적인 경우는 즉각적인 사건입니다. 코드가 이러한 문제를 일으키는 작업을 수행하면 브라우저가 즉시 실행합니다.

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();
<textarea id="log" rows="20" cols="40"></textarea>
<input id="inp">

log in, blur, log outIE를 제외한 모든 결과가 나타 납니다. 이러한 이벤트는 focus()직접 호출했기 때문에 발생하는 것이 아니라 를 호출 alert()했거나 팝업 창을 열었 기 때문에 발생 하거나 포커스를 이동하는 다른 모든 이벤트에 발생할 수 있습니다 .

이로 인해 다른 이벤트가 발생할 수도 있습니다. 예를 들어 i.onchange리스너 를 추가 하고 focus()호출이 초점을 맞추기 전에 입력에 무언가를 입력 하면 로그 순서는입니다 log in, change, blur, log out. 단, Opera에서는 그것이 log in, blur, log out, change있고 IE에서는 예외입니다 log in, change, log out, blur.

마찬가지로 click()제공하는 요소를 호출하면 onclick모든 브라우저에서 즉시 핸들러를 호출 합니다 (적어도 일관성이 있습니다!).

( on...여기서 직접 이벤트 처리기 속성을 사용하고 있지만 addEventListener에서도 마찬가지 attachEvent입니다.)

당신이 완료가없는에도 불구하고 당신의 코드에서 스레드되는 동안 이벤트가 발생 할 수있는 상황의 무리도있다 아무것도 를 유발하기는. 예 :

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';
};
<textarea id="log" rows="20" cols="40"></textarea>
<button id="act">alert</button>

치면 alert모달 대화 상자가 나타납니다. 대화를 닫을 때까지 더 이상 스크립트가 실행되지 않습니다. 아니. 기본 창 크기를 조정하면 alert in, resize, alert out텍스트 영역이 나타납니다.

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.

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:

  • 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.

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.

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.


I'd say yes - because virtually all existing (at least all non-trivial) javascript code would break if a browser's javascript engine were to run it asynchronously.

Add to that the fact that HTML5 already specifies Web Workers (an explicit, standardized API for multi-threading javascript code) introducing multi-threading into the basic Javascript would be mostly pointless.

(Note to others commenters: Even though setTimeout/setInterval, HTTP-request onload events (XHR), and UI events (click, focus, etc.) provide a crude impression of multi-threadedness - they are still all executed along a single timeline - one at a time - so even if we don't know their execution order beforehand, there's no need to worry about external conditions changing during the execution of an event handler, timed function or XHR callback.)


Yes, although you can still suffer some of the issues of concurrent programming (mainly race conditions) when using any of the asynchronous APIs such as setInterval and xmlhttp callbacks.


Yes, although Internet Explorer 9 will compile your Javascript on a separate thread in preparation for execution on the main thread. This doesn't change anything for you as a programmer, though.


JavaScript/ECMAScript is designed to live within a host environment. That is, JavaScript doesn't actually do anything unless the host environment decides to parse and execute a given script, and provide environment objects that let JavaScript actually be useful (such as the DOM in browsers).

I think a given function or script block will execute line-by-line and that is guaranteed for JavaScript. However, perhaps a host environment could execute multiple scripts at the same time. Or, a host environment could always provide an object that provides multi-threading. setTimeout and setInterval are examples, or at least pseudo-examples, of a host environment providing a way to do some concurrency (even if it's not exactly concurrency).


Actually, a parent window can communicate with child or sibling windows or frames that have their own execution threads running.


@Bobince is providing a really opaque answer.

Riffing off of Már Örlygsson's answer, Javascript is always single-threaded because of this simple fact: Everything in Javascript is executed along a single timeline.

That is the strict definition of a single-threaded programming language.


I would say that the specification does not prevent someone from creating an engine that runs javascript on multiple threads, requiring the code to perform synchronization for accessing shared object state.

I think the single-threaded non-blocking paradigm came out of the need to run javascript in browsers where ui should never block.

Nodejs has followed the browsers' approach.

Rhino engine however, supports running js code in different threads. The executions cannot share context, but they can share scope. For this specific case the documentation states:

..."Rhino guarantees that accesses to properties of JavaScript objects are atomic across threads, but doesn't make any more guarantees for scripts executing in the same scope at the same time.If two scripts use the same scope simultaneously, the scripts are responsible for coordinating any accesses to shared variables."

From reading Rhino documentation I conclude that that it can be possible for someone to write a javascript api that also spawns new javascript threads, but the api would be rhino-specific (e.g. node can only spawn a new process).

I imagine that even for an engine that supports multiple threads in javascript there should be compatibility with scripts that do not consider multi-threading or blocking.

Concearning browsers and nodejs the way I see it is:

  • Is all js code executed in a single thread? : Yes.

  • Can js code cause other threads to run? : Yes.

  • Can these threads mutate js execution context?: No. But they can (directly/indirectly(?)) append to the event queue.

So, in case of browsers and nodejs (and probably a lot of other engines) javascript is not multithreaded but the engines themselves are.


No.

I'm going against the crowd here, but bear with me. A single JS script is intended to be effectively single threaded, but this doesn't mean that it can't be interpreted differently.

Let's say you have the following code...

var list = [];
for (var i = 0; i < 10000; i++) {
  list[i] = i * i;
}

This is written with the expectation that by the end of the loop, the list must have 10000 entries which are the index squared, but the VM could notice that each iteration of the loop does not affect the other, and reinterpret using two threads.

First thread

for (var i = 0; i < 5000; i++) {
  list[i] = i * i;
}

Second thread

for (var i = 5000; i < 10000; i++) {
  list[i] = i * i;
}

I'm simplifying here, because JS arrays are more complicated then dumb chunks of memory, but if these two scripts are able to add entries to the array in a thread-safe way, then by the time both are done executing it'll have the same result as the single-threaded version.

While I'm not aware of any VM detecting parallelizable code like this, it seems likely that it could come into existence in the future for JIT VMs, since it could offer more speed in some situations.

Taking this concept further, it's possible that code could be annotated to let the VM know what to convert to multi-threaded code.

// 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;
}

Since Web Workers are coming to Javascript, it's unlikely that this... uglier system will ever come into existence, but I think it's safe to say Javascript is single-threaded by tradition.


Well, Chrome is multiprocess, and I think every process deals with its own Javascript code, but as far as the code knows, it is "single-threaded".

There is no support whatsoever in Javascript for multi-threading, at least not explicitly, so it does not make a difference.


I've tried @bobince's example with a slight modifications:

<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>

So, when you press Run, close alert popup and do a "single thread", you should see something like this:

click begin
click end
result = 20, should be 20

But if you try to run this in Opera or Firefox stable on Windows and minimize/maximize window with alert popup on screen, then there will be something like this:

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

I don't want to say, that this is "multithreading", but some piece of code had executed in a wrong time with me not expecting this, and now I have a corrupted state. And better to know about this behavior.


Try to nest two setTimeout functions within each other and they will behave multithreaded (ie; the outer timer won't wait for the inner one to complete before executing its function).

참고URL : https://stackoverflow.com/questions/2734025/is-javascript-guaranteed-to-be-single-threaded

반응형