다음과 같은 자바 스크립트 기능이 있습니다.
function myFunction(number) {
var x=number;
...
... more initializations
//here need to wait until flag==true
while(flag==false)
{}
...
... do something
}
문제는 자바 스크립트가 잠시 동안 멈춰서 내 프로그램을 멈춘다는 것입니다. 그래서 내 질문은 “busy-wait”없이 플래그가 true가 될 때까지 함수 중간에서 어떻게 기다릴 수 있습니까?
답변
브라우저의 자바 스크립트는 단일 스레드 (여기에 관련되지 않은 웹 작업자 제외)이고 자바 스크립트 실행의 한 스레드가 다른 스레드가 실행되기 전에 완료되기 때문에 다음과 같은 명령문이 있습니다.
while(flag==false) {}
단순히 영원히 실행되고 (또는 브라우저가 응답하지 않는 자바 스크립트 루프에 대해 불평 할 때까지) 페이지가 중단 된 것처럼 보이고 다른 자바 스크립트가 실행될 기회가 없으므로 플래그의 값을 변경할 수 없습니다.
좀 더 자세한 설명을 위해 Javascript는 이벤트 기반 언어 입니다. 즉, 인터프리터에게 제어권을 반환 할 때까지 Javascript를 실행합니다. 그런 다음 인터프리터로 돌아올 때만 Javascript는 이벤트 큐에서 다음 이벤트를 가져 와서 실행합니다.
타이머 및 네트워크 이벤트와 같은 모든 것은 이벤트 큐를 통해 실행됩니다. 따라서 타이머가 실행되거나 네트워크 요청이 도착하면 현재 실행중인 자바 스크립트를 “중단”하지 않습니다. 대신 이벤트가 Javascript 이벤트 큐에 들어간 다음 현재 실행중인 Javascript가 완료되면 다음 이벤트를 이벤트 큐에서 가져 와서 실행할 차례를 가져옵니다.
따라서와 같은 무한 루프를 수행 while(flag==false) {}
하면 현재 실행중인 Javascript가 완료되지 않으므로 다음 이벤트가 이벤트 큐에서 flag
가져 오지 않으므로의 값 이 변경되지 않습니다. 여기서 핵심은 자바 스크립트가 인터럽트 구동이 아니라는 것 입니다. 타이머가 실행될 때 현재 실행중인 자바 스크립트를 중단하지 않고 다른 자바 스크립트를 실행 한 다음 현재 실행중인 자바 스크립트를 계속합니다. 현재 실행중인 Javascript가 실행될 차례를 완료 할 때까지 기다리는 이벤트 큐에 넣습니다.
해야 할 일은 코드가 어떻게 작동하는지 다시 생각하고 flag
값이 변경 될 때 실행할 코드를 트리거하는 다른 방법을 찾는 것 입니다. Javascript는 이벤트 기반 언어로 설계되었습니다. 따라서 관심을 등록 할 수있는 이벤트가 무엇인지 파악하여 플래그가 변경 될 수있는 이벤트를 수신하고 해당 이벤트의 플래그를 검사하거나 다음에서 자신의 이벤트를 트리거 할 수 있습니다. 어떤 코드가 플래그를 변경 될 수 있습니다 또는 플래그 값을 변경 할 책임이 코드의 조각에의 값을 변경 할 때마다 코드가 콜백을 호출 할 수 플래그를 변경 무엇이든 콜백 함수를 구현할 수 있습니다 true
, 그것은 당신의 코드에 따라서 콜백 함수를 호출하고 플래그가 설정되면 실행하려는true
적시에 실행됩니다. 이것은 플래그 값을 지속적으로 확인하기 위해 일종의 타이머를 사용하는 것보다 훨씬 더 효율적입니다.
function codeThatMightChangeFlag(callback) {
// do a bunch of stuff
if (condition happens to change flag value) {
// call the callback to notify other code
callback();
}
}
답변
자바 스크립트는 단일 스레드이므로 페이지 차단 동작입니다. 다른 사람들이 제안한 지연 / 약속 접근 방식을 사용할 수 있지만 가장 기본적인 방법은 window.setTimeout
. 예
function checkFlag() {
if(flag == false) {
window.setTimeout(checkFlag, 100); /* this checks the flag every 100 milliseconds*/
} else {
/* do something*/
}
}
checkFlag();
다음은 자세한 설명이있는 좋은 튜토리얼입니다. 튜토리얼
편집하다
다른 사람들이 지적했듯이 가장 좋은 방법은 콜백을 사용하도록 코드를 재구성하는 것입니다. 그러나이 답변은 .NET을 사용하여 비동기 동작을 ‘시뮬레이션’할 수있는 방법을 알려줍니다 window.setTimeout
.
답변
Promise , async \ await 및 EventEmitter 를 사용하는 솔루션으로 어떤 종류의 루프도 전혀없이 플래그 변경에 즉시 반응 할 수 있습니다.
const EventEmitter = require('events');
const bus = new EventEmitter();
let lock = false;
async function lockable() {
if (lock) await new Promise(resolve => bus.once('unlocked', resolve));
....
lock = true;
...some logic....
lock = false;
bus.emit('unlocked');
}
EventEmitter
노드에 내장되어 있습니다. 브라우저에서 직접 포함해야합니다 (예 : https://www.npmjs.com/package/eventemitter3 패키지 사용).
답변
Async / Await가있는 ES6,
let meaningOfLife = false;
async function waitForMeaningOfLife(){
while (true){
if (meaningOfLife) { console.log(42); return };
await null; // prevents app from hanging
}
}
waitForMeaningOfLife();
setTimeout(()=>meaningOfLife=true,420)
답변
function waitFor(condition, callback) {
if(!condition()) {
console.log('waiting');
window.setTimeout(waitFor.bind(null, condition, callback), 100); /* this checks the flag every 100 milliseconds*/
} else {
console.log('done');
callback();
}
}
사용하다:
waitFor(() => window.waitForMe, () => console.log('got you'))
답변
Ecma Script 2017을 사용하면 async-await 및 while을 함께 사용할 수 있으며 변수가 true가 아니더라도 프로그램이 충돌하거나 잠그지 않습니다.
//First define some delay function which is called from async function
function __delay__(timer) {
return new Promise(resolve => {
timer = timer || 2000;
setTimeout(function () {
resolve();
}, timer);
});
};
//Then Declare Some Variable Global or In Scope
//Depends on you
var flag = false;
//And define what ever you want with async fuction
async function some() {
while (!flag)
await __delay__(1000);
//...code here because when Variable = true this function will
};
답변
Promise를 사용한 최신 솔루션
myFunction()
원래 질문에서 다음과 같이 수정할 수 있습니다
async function myFunction(number) {
var x=number;
...
... more initializations
await until(_ => flag == true);
...
... do something
}
until()
이 유틸리티 함수는 어디에 있습니까?
function until(conditionFunction) {
const poll = resolve => {
if(conditionFunction()) resolve();
else setTimeout(_ => poll(resolve), 400);
}
return new Promise(poll);
}
async / await 및 arrow 함수에 대한 일부 참조는 https://stackoverflow.com/a/52652681/209794 와 유사한 게시물에 있습니다.