program tip

flag = true까지 기다립니다.

radiobox 2020. 11. 13. 08:02
반응형

flag = true까지 기다립니다.


다음과 같은 자바 스크립트 기능이 있습니다.

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.


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

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)

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


($ .each) 객체를 반복하고 각 객체에서 오래 실행되는 작업 (중첩 된 ajax 동기화 호출 포함)을 실행하려면 다음을 수행합니다.

먼저 done=false각각에 대해 사용자 지정 속성을 설정합니다 .

그런 다음 재귀 함수에서 각각을 설정 done=true하고 setTimeout. (이 작업의 의미가 다른 모든 UI를 중지하려면 진행률 표시 줄을 표시하고 나는 동기 호출에 대해 자신을 용서 있도록 다른 모든 사용을 차단합니다.)

function start()
{
    GlobalProducts = getproductsfromsomewhere();
    $.each(GlobalProducts, function(index, product) {
         product["done"] = false;
    });

    DoProducts();
}
function DoProducts()
{
    var doneProducts = Enumerable.From(GlobalProducts).Where("$.done == true").ToArray(); //linqjs

    //update progress bar here

    var nextProduct = Enumerable.From(GlobalProducts).Where("$.done == false").First();

        if (nextProduct) {
            nextProduct.done = true;
            Me.UploadProduct(nextProduct.id); //does the long-running work

            setTimeout(Me.UpdateProducts, 500)
        }
}

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 와 유사한 게시물에 있습니다.


Lightbeard의 답변과 유사하게 다음 접근 방식을 사용합니다.

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function until(fn) {
    while (!fn()) {
        await sleep(0)
    }
}

async function myFunction(number) {
    let x = number
    ...
    ... more initialization

    await until(() => flag == true)

    ...
    ... do something
}

다음과 같이 @Kiran 접근 방식을 사용하려고했습니다.

checkFlag: function() {
  var currentObject = this; 
  if(flag == false) {
      setTimeout(currentObject.checkFlag, 100); 
   } else {
     /* do something*/
   }
}

(내가 사용하는 프레임 워크는 이런 방식으로 함수를 정의하도록 강제합니다). 그러나 실행이 checkFlag 함수 내부에 두 번째로 들어올 때 this내 개체가 아니기 때문에 성공하지 못했습니다 Window. 그래서 아래 코드로 끝냈습니다.

checkFlag: function() {
    var worker = setInterval (function(){
         if(flag == true){             
             /* do something*/
              clearInterval (worker);
         } 
    },100);
 }

//function a(callback){
setTimeout(function() {
  console.log('Hi I am order 1');
}, 3000);
 // callback();
//}

//function b(callback){
setTimeout(function() {
  console.log('Hi I am order 2');
}, 2000);
//   callback();
//}



//function c(callback){
setTimeout(function() {
  console.log('Hi I am order 3');
}, 1000);
//   callback();

//}

 
/*function d(callback){
  a(function(){
    b(function(){
      
      c(callback);
      
    });
    
  });
  
  
}
d();*/


async function funa(){
  
  var pr1=new Promise((res,rej)=>{
    
   setTimeout(()=>res("Hi4 I am order 1"),3000)
        
  })
  
  
   var pr2=new Promise((res,rej)=>{
    
   setTimeout(()=>res("Hi4 I am order 2"),2000)
        
  })
   
    var pr3=new Promise((res,rej)=>{
    
   setTimeout(()=>res("Hi4 I am order 3"),1000)
        
  })

              
  var res1 = await pr1;
  var res2 = await pr2;
  var res3 = await pr3;
  console.log(res1,res2,res3);
  console.log(res1);
   console.log(res2);
   console.log(res3);

}   
    funa();
              


async function f1(){
  
  await new Promise(r=>setTimeout(r,3000))
    .then(()=>console.log('Hi3 I am order 1'))
    return 1;                        

}

async function f2(){
  
  await new Promise(r=>setTimeout(r,2000))
    .then(()=>console.log('Hi3 I am order 2'))
         return 2;                   

}

async function f3(){
  
  await new Promise(r=>setTimeout(r,1000))
    .then(()=>console.log('Hi3 I am order 3'))
        return 3;                    

}

async function finaloutput2(arr){
  
  return await Promise.all([f3(),f2(),f1()]);
}

//f1().then(f2().then(f3()));
//f3().then(f2().then(f1()));
  
//finaloutput2();

//var pr1=new Promise(f3)







async function f(){
  console.log("makesure");
  var pr=new Promise((res,rej)=>{
  setTimeout(function() {
  console.log('Hi2 I am order 1');
}, 3000);
  });
    
  
  var result=await pr;
  console.log(result);
}

 // f(); 

async function g(){
  console.log("makesure");
  var pr=new Promise((res,rej)=>{
  setTimeout(function() {
  console.log('Hi2 I am order 2');
}, 2000);
  });
    
  
  var result=await pr;
  console.log(result);
}
  
// g(); 

async function h(){
  console.log("makesure");
  var pr=new Promise((res,rej)=>{
  setTimeout(function() {
  console.log('Hi2 I am order 3');
}, 1000);
  });
    
  
  var result=await pr;
  console.log(result);
}

async function finaloutput(arr){
  
  return await Promise.all([f(),g(),h()]);
}
  
//finaloutput();

 //h(); 
  
  
  
  
  
  


EventTarget API 와 함께 비 차단 자바 스크립트 사용

In my example, i need to wait for a callback before to use it. I have no idea when this callback is set. It can be before of after i need to execute it. And i can need to call it several time (everything async)

// bus to pass event
const bus = new EventTarget();

// it's magic
const waitForCallback = new Promise((resolve, reject) => {
    bus.addEventListener("initialized", (event) => {
        resolve(event.detail);
    });
});



// LET'S TEST IT !


// launch before callback has been set
waitForCallback.then((callback) => {
    console.log(callback("world"));
});


// async init
setTimeout(() => {
    const callback = (param) => { return `hello ${param.toString()}`; }
    bus.dispatchEvent(new CustomEvent("initialized", {detail: callback}));
}, 500);


// launch after callback has been set
setTimeout(() => {
    waitForCallback.then((callback) => {
        console.log(callback("my little pony"));
    });
}, 1000);


In my example, I log a new counter value every second:

var promises_arr = [];
var new_cntr_val = 0;

// fill array with promises
for (let seconds = 1; seconds < 10; seconds++) {
    new_cntr_val = new_cntr_val + 5;    // count to 50
    promises_arr.push(new Promise(function (resolve, reject) {
        // create two timeouts: one to work and one to resolve the promise
        setTimeout(function(cntr) {
            console.log(cntr);
        }, seconds * 1000, new_cntr_val);    // feed setTimeout the counter parameter
        setTimeout(resolve, seconds * 1000);
    }));
}

// wait for promises to finish
Promise.all(promises_arr).then(function (values) {
    console.log("all promises have returned");
});

참고URL : https://stackoverflow.com/questions/22125865/wait-until-flag-true

반응형