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 out
IE ie ie ie ie ie ie ie ie 。 이 전화했다고 터지는 것이 .focus()
일이 생길 수 요.alert()
또는 팝업 창을 열거나 포커스를 이동하는 다른 모든 항목을 열거나 합니다.
이로 인해 다른 이벤트도 발생할 수 있습니다.를 들어, 「」를 합니다.i.onchange
전에 을 입력해 주세요.focus()
를 해제하고 는 「」입니다.log in, change, blur, log out
)log in, blur, log out, change
곳더 알기 쉽게는) IE입니다.log in, change, log out, blur
.
로 " " 를 호출합니다.click()
에서는, 「」를 합니다.onclick
핸들러를 모든 브라우저에서 즉시 사용할 수 있습니다(적어도 이것은 일관성이 있습니다).
(direct)를 .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
는 Opera를 제외한 모든 열려 .★★★★★★★★★★★★★★★★★★
showModalDialog
하는 경우이 페이지의 스크립트는 바쁠 수 있습니다.대화상자는 스크립트를 계속 실행하도록 선택해도 크기 조정이나 흐림 등의 이벤트를 실행할 수 있습니다(오페라에서는 제외).
조금 전 IE에서 Sun Java Plugin을 사용하는 경우 애플릿에서 어떤 메서드를 호출해도 이벤트가 발생하거나 스크립트를 다시 입력할 수 있습니다.이것은 항상 타이밍에 민감한 버그이며, 그 이후 Sun이 수정했을 가능성이 있습니다(확실히 그러길 바랍니다).
아마 더 많을 거야테스트한지 꽤 지났는데 브라우저가 복잡해졌어요.
요약하면 대부분의 사용자에게 JavaScript는 엄격한 이벤트 구동형 단일 스레드 실행으로 보입니다.실제로는 그런 게 없어요.이 중 어느 정도가 단순한 버그인지, 어느 정도의 설계인지는 명확하지 않지만 복잡한 어플리케이션, 특히 크로스윈도/프레임 스크립팅 어플리케이션을 작성할 경우 간헐적이고 디버깅하기 어려운 방법으로 문제가 발생할 수 있습니다.
최악의 경우 모든 이벤트 응답을 간접하여 동시성 문제를 해결할 수 있습니다.큐를 합니다.setInterval
, 이 하는 것이 복잡한 응용 프로그램에서 사용하려는 프레임워크를 작성하는 경우 이 작업을 수행하는 것이 좋습니다. postMessage
또, 장래의 크로스 캐리어 스크립팅의 고통도 경감할 수 있을 것으로 기대하고 있습니다.
브라우저의 Javascript 엔진이 비동기적으로 실행할 경우, 거의 모든 기존(적어도 모든 사소한 것이 아닌) Javascript 코드가 깨지기 때문입니다.
게다가 HTML5가 이미 Web Workers(멀티 스레드 자바스크립트 코드를 위한 명시적이고 표준화된 API)를 기본 자바스크립트에 도입하는 것은 거의 무의미하다.
(다른 코멘트 담당자에 대한 주의:그럼에도 불구하고.setTimeout/setInterval
HTTP 요청 온로드 이벤트(XHR) 및 UI 이벤트(클릭, 포커스 등)는 멀티 스레드화의 대략적인 인상을 줍니다.이러한 이벤트들은 모두 한 번에 하나씩 하나의 타임라인에 따라 실행됩니다." function callback")r, function "XHR" 입니다
네, 하지만 set와 같은 비동기 API를 사용할 때 동시 프로그래밍(주로 레이스 조건)의 문제가 발생할 수 있습니다.인터벌 및 xmlhttp 콜백
네, Internet Explorer 9는 메인 스레드에서 실행할 준비를 위해 별도의 스레드에 Javascript를 컴파일합니다.프로그래머로서 아무것도 변하지 않습니다.
이 사양은 여러 스레드 상에서 Javascript를 실행하는 엔진을 작성하는 것을 방해하지 않으며, 공유 객체 상태에 액세스하기 위해 코드를 동기화해야 합니다.
싱글 스레드 논블로킹 패러다임은 ui가 절대 차단해서는 안 되는 브라우저에서 javascript를 실행해야 하는 필요성에서 나온 것이라고 생각합니다.
Nodejs는 브라우저의 접근방식을 따르고 있습니다.
그러나 Rhino 엔진은 다른 스레드에서 js 코드를 실행할 수 있도록 지원합니다.실행은 컨텍스트를 공유할 수 없지만 범위를 공유할 수 있습니다.이 경우 문서에는 다음과 같이 기술되어 있습니다.
..."Rino는 JavaScript 객체의 속성에 대한 액세스가 스레드 전체에 걸쳐 원자적인 것임을 보장하지만 동일한 범위에서 동시에 실행되는 스크립트에 대해서는 더 이상 보장하지 않습니다.두 스크립트가 동시에 동일한 범위를 사용하는 경우 스크립트는 공유 변수에 대한 액세스를 조정합니다."
Rhino 문서를 읽으면 새로운 javascript 스레드도 생성하는 javascript api를 작성하는 것은 가능하지만 api는 코뿔소 고유의 것입니다(예를 들어 노드는 새로운 프로세스만 생성할 수 있습니다).
javascript에서 여러 스레드를 지원하는 엔진이라도 멀티 스레드나 블로킹을 고려하지 않는 스크립트와의 호환성이 있다고 생각합니다.
브라우저와 노드를 내 견해대로 설정하는 방법은 다음과 같습니다.
-
- 모든 js 코드가 단일 스레드로 실행됩니까?- 네. - 네.
-
- js 코드가 다른 스레드를 실행할 수 있습니까? : 네.
-
- 이러한 스레드는 js 실행 컨텍스트를 변환할 수 있습니까?아니요. 그러나 청취자가 실행 컨텍스트를 변환할 수 있는 이벤트 큐에 직접/간접(?)을 추가할 수 있습니다.하지만 속지 마세요, 청취자들은 다시 본선에서 원자적으로 움직입니다.
따라서 브라우저와 nodejs(그리고 다른 많은 엔진)의 경우 javascript는 멀티스레드가 아니라 엔진 자체가 멀티스레드입니다.
웹 작업자에 대한 업데이트:
웹워커의 존재는 javascript를 멀티스레드화할 수 있다는 것을 더욱 정당화한다.따라서 다른 스레드에서 실행되는 코드를 javascript로 작성할 수 있다.
그러나 웹 워커는 실행 컨텍스트를 공유할 수 있는 기존 스레드의 문제를 해결하지 않습니다.위의 규칙 2와 3은 그대로 적용되지만, 이번에는 사용자(js 코드 라이터)가 javascript에서 스레드 코드를 작성합니다.
고려해야 할 것은 효율성(동시성이 아닌) 관점에서 생성된 스레드의 수뿐입니다.아래를 참조해 주세요.
워커 인터페이스는 실제 OS 수준의 스레드를 생성합니다.또한 주의 깊은 프로그래머는 주의하지 않으면 동시성이 코드에 "흥미로운" 영향을 미칠 수 있다고 우려할 수 있습니다.
그러나 웹 워커는 다른 스레드와의 통신 포인트를 신중하게 제어하고 있기 때문에 동시성 문제를 일으키는 것은 매우 어렵습니다.스레드세이프가 아닌 컴포넌트나 DOM에는 접근할 수 없습니다.또한 특정 데이터를 직렬화된 개체를 통해 스레드 안팎으로 전달해야 합니다.그러니까 코드에 문제를 일으키려면 정말 열심히 해야 해.
추신.
이론 외에, 항상 가능한 코너 케이스와 수용된 답변에 기재된 버그에 대해 준비합니다.
JavaScript/ECMAScript는 호스트 환경 내에서 동작하도록 설계되었습니다.즉, 호스트 환경에서 특정 스크립트를 해석 및 실행하고 실제로 JavaScript가 유용한 환경 객체(브라우저의 DOM 등)를 제공하지 않는 한 JavaScript는 실제로 아무것도 수행하지 않습니다.
주어진 함수나 스크립트 블록은 한 줄 한 줄 실행되며 이는 JavaScript에 보장된다고 생각합니다.그러나 호스트 환경에서는 여러 스크립트를 동시에 실행할 수 있습니다.또는 호스트 환경에서는 항상 멀티 스레딩을 제공하는 개체를 제공할 수 있습니다. setTimeout
★★★★★★★★★★★★★★★★★」setInterval
는, (정확한 동시성이 아닌 경우라도) 어느 정도의 동시성을 실현하는 방법을 제공하는 호스트 환경의 예(적어도 의사적인 유사성)입니다.
실제로 상위 창은 자체 실행 스레드가 실행 중인 하위 창 또는 형제 창 또는 프레임과 통신할 수 있습니다.
@Bobince는 매우 불투명한 답변을 하고 있다.
Marr Orlygsson의 답변에서 벗어나 Javascript는 항상 싱글 스레드화되어 있습니다.이는 Javascript의 모든 것이 하나의 타임라인에 따라 실행된다는 단순한 사실 때문입니다.
이것은 싱글 스레드 프로그래밍 언어의 엄격한 정의입니다.
아니요.
난 여기 군중들과 맞서고 있지만, 조금만 참아줘.단일 JS 스크립트는 효과적으로 단일 스레드화되도록 설계되었지만 다르게 해석할 수 없는 것은 아닙니다.
예를 들어 다음과 같은 코드가 있다고 칩시다.
var list = [];
for (var i = 0; i < 10000; i++) {
list[i] = i * i;
}
이것은 루프가 끝날 때까지 목록에는 인덱스의 제곱인 10000개의 엔트리가 있어야 하지만 VM은 루프의 각 반복이 서로 영향을 미치지 않는다는 것을 알아차리고 2개의 스레드를 사용하여 재해석할 수 있습니다.
첫 번째 스레드
for (var i = 0; i < 5000; i++) {
list[i] = i * i;
}
두 번째 스레드
for (var i = 5000; i < 10000; i++) {
list[i] = i * i;
}
JS 어레이가 멍청한 메모리 청크보다 더 복잡하기 때문에 단순하게 설명하겠습니다.그러나 이 두 스크립트가 스레드 세이프 방식으로 어레이에 엔트리를 추가할 수 있다면 두 스크립트가 모두 실행되는 시점에는 싱글 스레드 버전과 동일한 결과를 얻을 수 있습니다.
이와 같은 병렬 가능한 코드를 VM이 감지하는 것은 잘 모르지만, 상황에 따라서는 더 빠른 속도를 제공할 수 있기 때문에 향후 JIT VM에 이러한 코드가 제공될 수 있습니다.
이 개념을 더 발전시키면 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;
}
웹 워커가 Javascript에 오기 때문에, 이것이...더 추악한 시스템이 등장하겠지만, 자바스크립트는 전통에 따라 싱글 스레드라고 해도 무방할 것 같습니다.
크롬은 멀티프로세싱으로 모든 프로세스가 독자적인 Javascript 코드를 다루고 있다고 생각합니다만, 코드가 아는 한 싱글 스레드입니다.
Javascript에서는 적어도 명시적으로 멀티스레딩을 지원하지 않기 때문에 차이가 없습니다.
@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
그러나 Windows에서 Opera 또는 Firefox를 안정적으로 실행하고 경고 팝업이 화면에 나타나는 창을 최소화/최대화하려고 하면 다음과 같은 현상이 나타납니다.
click begin
resize
click end
result = 15, should be 20
이것은 「멀티스레딩」이라고는 말할 수 없지만, 코드 조각이 잘못된 시간에 실행되어, 내가 이것을 예상하지 못한 상태로 되어 버렸습니다.그리고 이 행동에 대해 아는 게 좋을 거야
Javascript 엔진은 싱글 스레드여야 하지만 Javascript 런타임은 싱글 스레드일 필요가 없습니다.
자바스크립트 엔진이 뭐죠?그것은 실제 JS 코드를 실행하는 인터프리터입니다.엔진에 호스트가 필요합니다.혼자서는 달릴 수 없어요.호스트는 Javascript 런타임입니다.
예를 들어 크롬 브라우저에서 실행되는 V8 엔진은 단일 스레드 방식입니다.크롬 브라우저는 런타임이며 V8 엔진을 지원하는 다른 프로세스/스레드가 있습니다.
이 기사가 잘 설명되어 있는 곳에서 확인하실 수 있습니다.도움이 된다면, 잊지 말고 다시 투표해 주세요:)
2개의 setTimeout 함수를 서로 중첩하면 멀티스레드 기능이 동작합니다(즉, 외부 타이머는 내부 타이머가 완료될 때까지 기다리지 않습니다).
언급URL : https://stackoverflow.com/questions/2734025/is-javascript-guaranteed-to-be-single-threaded
'sourcecode' 카테고리의 다른 글
Python은 긴 문자열을 잘라냅니다. (0) | 2023.01.20 |
---|---|
Panda의 지도, 적용 지도, 적용 방법의 차이 (0) | 2023.01.15 |
베이스 테이블 또는 뷰를 찾을 수 없음: 1146 테이블 Larabel 5 (0) | 2023.01.15 |
JSON Atribute (0) | 2023.01.15 |
Vue의 돌연변이 및 작업이 작동하지 않음 (0) | 2023.01.15 |