等到flag = true

ila*_*man 68 javascript synchronization

我有这样的javascript函数:

function myFunction(number) {

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

    ...
    ... do something

}
Run Code Online (Sandbox Code Playgroud)

问题是javascript被困在了一段时间并且卡住了我的程序.所以我的问题是如何才能在函数中间等待,直到flag为true而没有"busy-wait"?

Kir*_*ran 83

Javascript是单线程的,因此页面阻塞行为.您可以使用其他人建议的延迟/承诺方法,但最基本的方法是使用window.setTimeout.例如

function checkFlag() {
    if(flag == false) {
       window.setTimeout(checkFlag, 100); /* this checks the flag every 100 milliseconds*/
    } else {
      /* do something*/
    }
}
checkFlag();
Run Code Online (Sandbox Code Playgroud)

这是一个很好的教程,有进一步的解释:教程

编辑

正如其他人所指出的,最好的方法是重新构造代码以使用回调.但是,这个答案应该让您了解如何使用"模拟"异步行为window.setTimeout.

  • 这是一个很好的答案。在浏览了许多技术论坛后,我几乎放弃了。我认为它非常适合我,因为我正在返回一个值。它也适用于 Internet Explorer。非常感谢。 (2认同)
  • 如果出于任何原因我们需要向 checkFlag 函数发送参数,那么我们必须使用匿名/箭头函数,例如 `window.setTimeout( () => { checkFlag(params); }, 100);` (2认同)

jfr*_*d00 58

因为浏览器中的javascript是单线程的(除了这里没有涉及的webworkers)并且javascript执行的一个线程在另一个可以运行之前运行完成,你的语句:

while(flag==false) {}
Run Code Online (Sandbox Code Playgroud)

将永远运行(或直到浏览器抱怨无响应的javascript循环),页面将显示为挂起,没有其他javascript将有机会运行,因此标志的值永远不会被更改.

对于更多解释,Javascript是一种事件驱动的语言.这意味着它运行一段Javascript,直到它将控制权返回给解释器.然后,只有当它返回到解释器时,Javascript才从事件队列中获取下一个事件并运行它.

计时器和网络事件等所有内容都通过事件队列运行.因此,当计时器触发或网络请求到达时,它不会"中断"当前运行的Javascript.相反,一个事件被放入Javascript事件队列中,然后,当当前运行的Javascript完成时,下一个事件将从事件队列中拉出并轮到它运行.

因此,当您执行无限循环时while(flag==false) {},当前运行的Javascript永远不会完成,因此下一个事件永远不会从事件队列中拉出,因此flag永远不会更改值.它们的关键在于Javascript不是中断驱动的.当计时器触发时,它不会中断当前运行的Javascript,运行其他一些Javascript,然后让当前运行的Javascript继续.它只是放入事件队列中等待,直到当前运行的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();
    }
}
Run Code Online (Sandbox Code Playgroud)


Lig*_*ard 14

使用 Promise 的现代解决方案

myFunction() 在原始问题中可以修改如下

async function myFunction(number) {

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

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

    ...
    ... do something

}
Run Code Online (Sandbox Code Playgroud)

until()这个效用函数在哪里

function until(conditionFunction) {

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

  return new Promise(poll);
}
Run Code Online (Sandbox Code Playgroud)

一些对 async/await 和箭头函数的引用在类似的帖子中:https : //stackoverflow.com/a/52652681/209794

  • 这是我见过的唯一解决方案,它可以轻松地让您“等待”信号,但在满足条件之前不会从 myFunction“返回”。 (4认同)

小智 13

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

使用:

waitFor(() => window.waitForMe, () => console.log('got you'))
Run Code Online (Sandbox Code Playgroud)


Ste*_*ers 9

就调用代码的可读性和实现代码的简洁性而言最简单:

const until = (predFn) => {
  const poll = (done) => (predFn() ? done() : setTimeout(() => poll(done), 500));
  return new Promise(poll);
};
Run Code Online (Sandbox Code Playgroud)

调用代码示例:

await until(() => { myBankBalance > 1000000 });
Run Code Online (Sandbox Code Playgroud)

更详细的例子:

https://replit.com/@SteveChambers1/Javascript-until-function?v=1


tdx*_*ius 8

我通过实施以下方法解决了这个问题。

const waitUntil = (condition) => {
    return new Promise((resolve) => {
        let interval = setInterval(() => {
            if (!condition()) {
                return
            }

            clearInterval(interval)
            resolve()
        }, 100)
    })
}
Run Code Online (Sandbox Code Playgroud)

现在,每当您想等到满足某个条件时,都可以这样调用。

await waitUntil(() => /* your condition */)
Run Code Online (Sandbox Code Playgroud)


Cod*_*rer 7

具有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)
Run Code Online (Sandbox Code Playgroud)

  • 根据您的使用情况,稍微睡眠一下可能会有所帮助,而不是“await null”。`等待新的 Promise(resolve => setTimeout(resolve, 10))` (2认同)

Yar*_*kij 7

使用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');
}
Run Code Online (Sandbox Code Playgroud)

EventEmitter内置在节点中。在浏览器中,您需要自己添加它,例如使用以下程序包:https : //www.npmjs.com/package/eventemitter3


Top*_*rak 5

使用Ecma Script 2017,您可以使用async-await和while一起执行此操作,而不会崩溃或锁定程序,即使变量永远不会为真

//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
};
Run Code Online (Sandbox Code Playgroud)