Wait until flag=true

2019-01-04 02:08发布

I have javascript function like this:

function myFunction(number) {

    var x=number;
    ...
    ... more initializations
    //here need to wait until flag==true
    while(flag==false)
    {}

    ...
    ... do something

}

The problem is that the javascript is stuck in the while and stuck my program. so my question is how can I wait in the middle of the function until flag is true without "busy-wait"?

9条回答
女痞
2楼-- · 2019-01-04 02:10

Solution using Promise, async\await and EventEmitter which allows to react immediate on flag change without any kind of loops at all

const EventEmitter = require('events'); 
const lock = false;
const bus = new EventEmitter();

async function lockable() {
    if (lock) await new Promise(resolve => bus.once('unlocked', resolve));
    ....
    lock = true;
    ...some logic....
    lock = false;
    bus.emit('unlocked');
}

EventEmitter is builtin in node. In browser you shall need to include it by your own, for example using this package: https://www.npmjs.com/package/eventemitter3

查看更多
劫难
3楼-- · 2019-01-04 02:10

Because javascript in a browser is single threaded (except for webworkers which aren't involved here) and one thread of javascript execution runs to completion before another can run, your statement:

while(flag==false) {}

will simply run forever (or until the browser complains about a non-responsive javascript loop), the page will appear to be hung and no other javascript will ever get a chance to run, thus the flag's value can never be changed.

For a little more explanation, Javascript is an event driven language. That means that it runs a piece of Javascript until it returns control back to the interpreter. Then, only when it returns back to the interpreter, Javascript gets the next event from the event queue and runs it.

All things like timers and network events run through the event queue. So, when a timer fires or a network request arrives, it does not ever "interrupt" the currently running Javascript. Instead, an event gets put in the Javascript event queue and then, when the currently running Javascript finishes, the next event is pulled from the event queue and it gets its turn to run.

So, when you do an infinite loop such as while(flag==false) {}, the currently running Javascript never finishes and thus the next event is never pulled from the event queue and thus the value of flag never gets changed. They key here is that Javascript is not interrupt driven. When a timer fires, it does not interrupt the currently running Javascript, run some other Javascript and then let the currently running Javascript continue. It just gets put in the event queue waiting until the currently running Javascript is done to get its turn to run.


What you need to do is rethink how your code works and find a different way to trigger whatever code you want to run when the flag value changes. Javascript is designed as an event-driven language. So, what you need to do is figure out what events you can register an interest in so you can either listen for the event that might cause the flag to change and you can examine the flag on that event or you can trigger your own event from whatever code might change the flag or you can implement a callback function that whatever code changes that flag can call your callback whenever the piece of code responsible for changing the flag value would change it's value to true, it just calls the callback function and thus your code that wants to run when the flag gets set to true will get to run at the right time. This is much, much more efficient than trying to use some sort of timer to constantly check the flag value.

function codeThatMightChangeFlag(callback) {
    // do a bunch of stuff
    if (condition happens to change flag value) {
        // call the callback to notify other code
        callback();
    }
}
查看更多
Fickle 薄情
4楼-- · 2019-01-04 02:13

//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(); 
  
  
  
  
  
  

查看更多
混吃等死
5楼-- · 2019-01-04 02:17

With Ecma Script 2017 You can use async-await and while together to do that And while will not crash or lock the program even variable never be 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
};

查看更多
欢心
6楼-- · 2019-01-04 02:21

Modern solution using Promise

myFunction() in the original question can be modified as follows

async function myFunction(number) {

    var x=number;
    ...
    ... more initializations

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

    ...
    ... do something

}

where until() is this utility function

function until(conditionFunction) {

  const poll = resolve => {
    if(conditionFunction()) resolve();
    else setTimeout(_ => poll(resolve), 400);
  }

  return new Promise(poll);
}

Some references to async/await and arrow functions are in a similar post: https://stackoverflow.com/a/52652681/209794

查看更多
贪生不怕死
7楼-- · 2019-01-04 02:24

ES6 with Async / Await ,

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)
查看更多
登录 后发表回答