[javascript] JavaScript는 단일 스레드로 보장됩니까?

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



답변

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

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

(* : 브라우저가 하나의 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()호출을 unfocuses 및 로그 순서는 log in, change, blur, log out그것이 어디 오페라를 제외 log in, blur, log out, change하고 IE 곳의 (더 적은 explicably) 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텍스트 영역에 나타납니다.

모달 대화 상자가 열려있는 동안 창의 크기를 조정하는 것이 불가능하다고 생각할 수도 있지만 그렇지 않습니다. Linux에서는 원하는만큼 창의 크기를 조정할 수 있습니다. Windows에서는 그렇게 쉽지는 않지만 화면 해상도가 창에 맞지 ​​않는 더 큰 화면에서 더 작은 화면으로 변경하면 화면 크기가 조정됩니다.

스크립트가 스레드되어 있기 때문에 사용자가 브라우저와 활발한 상호 작용을하지 않을 때 발생할 수 resize있는 것은 유일하다고 생각할 수도 있습니다 scroll. 그리고 단일 창문의 경우 당신이 옳을 수도 있습니다. 그러나 크로스 윈도우 스크립팅을 수행하는 즉시 모든 기능이 작동합니다. 사용 중일 때 모든 창 / 탭 / 프레임을 차단하는 Safari 이외의 모든 브라우저의 경우 별도의 실행 스레드에서 실행되고 관련 이벤트 처리기가 발생하도록 다른 문서의 코드에서 문서와 상호 작용할 수 있습니다. 불.

스크립트가 여전히 스레드되는 동안 생성 될 수있는 이벤트가 발생할 수있는 위치는 다음과 같습니다.

  • 모달 팝업은 (시 alert, confirm, prompt), 열려있는 모든 브라우저하지만 오페라에있다;

  • showModalDialog를 지원하는 브라우저에;

  • 스크립트를 계속 실행하도록 선택하더라도 “이 페이지의 스크립트가 사용 중일 수 있습니다 …”대화 상자가 표시됩니다. 스크립트가 중간에있는 동안에도 크기 조정 및 흐림 효과와 같은 이벤트가 발생하고 처리됩니다. Opera를 제외하고 사용 중입니다.

  • 얼마 전에 필자는 Sun Java Plugin을 사용하는 IE에서 애플릿의 메소드를 호출하면 이벤트가 발생하고 스크립트를 다시 입력 할 수 있습니다. 이것은 항상 타이밍에 민감한 버그였으며 썬이 그 이후로 수정했을 가능성이 있습니다 (확실히 바랍니다).

  • 아마 더. 이것을 테스트 한 지 오래되었습니다. 브라우저는 그 이후로 복잡해졌습니다.

요약하자면, 대부분의 사용자에게 JavaScript는 대부분 이벤트 중심의 단일 실행 스레드를 갖는 것으로 보입니다. 실제로는 그런 것이 없습니다. 이 중 얼마나 많은 부분이 단순히 버그인지, 고의적 인 디자인인지는 확실하지 않지만, 복잡한 응용 프로그램, 특히 크로스 윈도우 / 프레임 스크립팅 응용 프로그램을 작성하는 경우, 당신을 물릴 수있는 모든 기회가 있습니다. 디버그하기 어려운 방법.

최악의 상황이 최악의 경우 모든 이벤트 응답을 간접적으로 지정하여 동시성 문제를 해결할 수 있습니다. 이벤트가 들어 오면 이벤트를 큐에 버리고 나중에 setInterval함수 에서 큐를 순서대로 처리하십시오 . 복잡한 응용 프로그램에서 사용하려는 프레임 워크를 작성하는 경우이 작업을 수행하는 것이 좋습니다. postMessage또한 앞으로 크로스 문서 스크립팅의 고통을 진정으로 달래줄 것입니다.


답변

브라우저의 자바 스크립트 엔진이 비동기 적으로 실행하면 거의 모든 기존 (사소하지 않은) 자바 스크립트 코드가 작동하지 않기 때문에 예라고 대답하고 싶습니다.

HTML5가 이미 멀티 스레딩을 기본 자바 스크립트에 도입하는 웹 워커 (멀티 스레딩 자바 스크립트 코드를위한 명시적이고 표준화 된 API)를 지정 한다는 사실 은 무의미합니다.

( 다른 사람들의 덧글에 대한 참고 : 비록 setTimeout/setInterval하나 – – 그들은 여전히 하나의 타임 라인을 따라 실행, HTTP 요청은 이벤트 (XHR), 및 UI 이벤트 (클릭, 초점 등) 멀티 쓰레드 특성의 조잡한 느낌을 제공을 온로드 시간-따라서 사전에 실행 순서를 모르더라도 이벤트 핸들러, 시간 함수 또는 XHR 콜백을 실행하는 동안 외부 조건이 변경되는 것에 대해 걱정할 필요가 없습니다.)


답변

예. setInterval 및 xmlhttp 콜백과 같은 비동기 API를 사용할 때 동시 프로그래밍 (주로 경쟁 조건) 문제가 여전히 발생할 수 있습니다.


답변

예, Internet Explorer 9은 기본 스레드에서 실행하기 위해 별도의 스레드에서 Javascript를 컴파일합니다. 그래도 프로그래머에게는 아무런 변화가 없습니다.


답변

나는 스펙이 누군가가 여러 스레드에서 자바 스크립트 를 실행 하는 엔진생성하는 것을 막지 못한다고 말할 것입니다. 에서 공유 객체 상태에 액세스하기 위해 코드를 동기화해야합니다.

단일 스레드 비 차단 패러다임브라우저 에서 자바 스크립트를 실행할 필요가 있다고 생각 합니다. ui가 차단해서는 안되는 에서 .

Nodejs브라우저의 접근 방식을 따랐습니다. .

그러나 Rhino 엔진 은 다른 스레드에서 js 코드 실행을 지원합니다 . 실행은 컨텍스트를 공유 할 수 없지만 범위를 공유 할 수 있습니다. 이 특정 사례의 경우 설명서에 다음과 같이 명시되어 있습니다.

… “Rhino는 JavaScript 객체의 속성에 대한 액세스가 스레드 전체에서 원자 성임을 보장하지만 동일한 범위에서 동시에 동일한 범위에서 실행되는 스크립트를 더 이상 보장하지 않습니다. 두 스크립트가 동일한 범위를 동시에 사용 하면 스크립트는 공유 변수에 대한 액세스 조정을 담당합니다 . “

Rhino 문서를 읽음으로써 누군가가 새로운 자바 스크립트 스레드를 생성하는 자바 스크립트 API를 작성할 수 있지만, API는 코뿔소에 따라 다릅니다 (예 : 노드는 새로운 프로세스 만 스폰 할 수 있음).

자바 스크립트에서 여러 스레드를 지원하는 엔진의 경우에도 멀티 스레딩 또는 차단을 고려하지 않는 스크립트와의 호환성이 있어야한다고 생각합니다.

Concearning 브라우저를 하고 nodejs 방법 나는 그것이 참조 :

    1. 되어 모든 JS의 코드는 실행 단일 스레드 ? : 예.
    1. JS 원인 코드를 다른 쓰레드가 실행 ? : 예.
    1. 이 스레드 수 의 mutate JS 실행 컨텍스트가 : 아니요 그러나받는 사람 수 (직접 / 간접적으로 ()?) APPEND 이벤트 큐에 있는
      청취자 수있는 실행 컨텍스트를 변이 . 그러나 속지 마십시오. 리스너 는 기본 스레드에서 다시 원자 적으로 실행 됩니다.

따라서 브라우저 및 nodejs (및 아마도 다른 많은 엔진)의 경우 javascript는 다중 스레드가 아니지만 엔진 자체는 입니다.


웹 작업자에 대한 업데이트 :

웹 작업자의 존재는 누군가가 별도의 스레드에서 실행될 자바 스크립트로 코드를 만들 수 있다는 점에서 자바 스크립트가 멀티 스레드 될 수 있음을 더 정당화합니다.

그러나 웹 작업자는 실행 컨텍스트를 공유 할 수 있는 기존 스레드의 문제를 해결하지 않습니다 . 위의 규칙 2와 3은 여전히 ​​적용됩니다 되지만 이번에는 스레드 코드가 사용자 (js 코드 작성기)가 javascript로 작성됩니다.

고려해야 할 유일한 것은 효율성 (및 동시성이 아닌) 에서 생성 된 스레드 수입니다. 아님) 관점 . 아래를보십시오 :

나사산 안전 정보 :

Worker 인터페이스는 실제 OS 수준 스레드를 생성하며, 신중한 프로그래머는주의하지 않으면 동시성이 코드에 “흥미로운”영향을 줄 수 있다고 우려 할 수 있습니다.

그러나 웹 작업자는 다른 스레드와의 통신 지점 을 신중하게 제어 하므로 실제로 동시성 문제를 일으키는 것은 매우 어렵습니다 . 스레드로부터 안전하지 않은 구성 요소 나 DOM에 액세스 할 수 없습니다. 그리고 직렬화 된 객체를 통해 특정 데이터를 스레드 안팎으로 전달해야합니다. 따라서 코드에 문제를 일으키려면 정말 열심히 노력해야합니다.


추신

이론 외에도 항상 허용되는 답변 에 설명 된 가능한 코너 사례 및 버그에 대해 준비 하십시오.


답변

JavaScript / ECMAScript는 호스트 환경 내에서 작동하도록 설계되었습니다. 즉, 호스트 환경이 주어진 스크립트를 구문 분석하고 실행하기로 결정하고 JavaScript가 실제로 유용한 브라우저 (예 : 브라우저의 DOM)가 될 수있는 환경 객체를 제공하지 않는 한 JavaScript는 실제로 아무것도 하지 않습니다 .

주어진 함수 또는 스크립트 블록이 한 줄씩 실행되며 JavaScript에서 보장된다고 생각합니다. 그러나 호스트 환경은 동시에 여러 스크립트를 실행할 수 있습니다. 또는 호스트 환경은 항상 멀티 스레딩을 제공하는 객체를 제공 할 수 있습니다. setTimeout그리고 setInterval예, 또는 적어도 의사 예에서, 호스트 환경의 (정확히 동시성 아니더라도) 일부 병행 할 수있는 방법을 제공한다.


답변

실제로 부모 창은 자체 실행 스레드가 실행중인 자식 창 또는 형제 창 또는 프레임과 통신 할 수 있습니다.