繁体   English   中英

等到满足条件或在javascript中传递超时

[英]wait until condition is met or timeout is passed in javascript

我需要让代码休眠,直到满足某些条件或通过 3 秒超时。 然后返回一个简单的字符串。 无论如何我可以做到这一点吗?

// this function needs to return a simple string 

function something() { 

    var conditionOk = false;

    var jobWillBeDoneInNMiliseconds = Math.floor(Math.random() * 10000);

    setTimeout(function() {

        // I need to do something here, but I don't know how long it takes
        conditionOk = true; 

    }, jobWillBeDoneInNMiliseconds);


    // I need to stop right here until
    // stop here until ( 3000 timeout is passed ) or ( conditionOk == true )
    StopHereUntil( conditionOk, 3000 );

    return "returned something"; 
}

这就是我要做的:

我让浏览器滚动到页面底部,然后将调用一些 ajax 函数来获取评论(我无法控制它)。 现在我需要等到评论出现在带有“.comment”类的文档中。

我需要getComments()函数将评论作为 json 字符串返回。

function getComments() {

    window.scrollTo(0, document.body.scrollHeight || document.documentElement.scrollHeight);

  var a = (document.querySelectorAll('div.comment'))

  // wait here until  (  a.length > 0  ) or ( 3 second is passed )

  // then I need to collect comments
  var comments = [];
  document.querySelectorAll('div.comment p')
    .forEach(function(el){      
        comments.push(el.text());
    });

  return JSON.stringify(comments);
} 

getComments();

我遇到了这个问题,没有一个解决方案令人满意。 我需要等到某个元素出现在 DOM 中。 所以我接受了hedgehog125的回答并根据我的需要进行了改进。 我认为这回答了最初的问题。

const sleepUntil = async (f, timeoutMs) => {
    return new Promise((resolve, reject) => {
        const timeWas = new Date();
        const wait = setInterval(function() {
            if (f()) {
                console.log("resolved after", new Date() - timeWas, "ms");
                clearInterval(wait);
                resolve();
            } else if (new Date() - timeWas > timeoutMs) { // Timeout
                console.log("rejected after", new Date() - timeWas, "ms");
                clearInterval(wait);
                reject();
            }
        }, 20);
    });
}

用法(异步/等待承诺):

try {
    await sleepUntil(() => document.querySelector('.my-selector'), 5000);
    // ready
} catch {
    // timeout
}

用法(.then 承诺):

sleepUntil(() => document.querySelector('.my-selector'), 5000)
    .then(() => {
        // ready
    }).catch(() => {
        // timeout
    });

您应该能够使用Promise.race来实现这一点。 这是一个基本示例:

 let promise1 = new Promise(resolve => { setTimeout(resolve, 500, 'one'); }); let promise2 = new Promise(resolve => { setTimeout(resolve, 800, 'two'); }); async function fetchAndLogResult() { let result = await Promise.race([promise1, promise2]); console.log(result); } fetchAndLogResult();

这是一个替代版本,虽然不使用async / await ,但更简洁:

 let promise1 = new Promise(resolve => { setTimeout(resolve, 500, 'one'); }); let promise2 = new Promise(resolve => { setTimeout(resolve, 800, 'two'); }); Promise.race([promise1, promise2]).then(result => console.log(result));

在 JavaScript 中,没有办法等待。 您可以使用settimeout也可以使用 while 循环(请记住,在这种情况下脚本无法运行,然后页面可能会变得无响应)。

设置超时

// this function needs to return a simple string 

function something() { 

    conditionOk = false;

    var jobWillBeDoneInNMiliseconds = Math.floor(Math.random() * 10000);

    timeout = setTimeout(function() {

        // I need to do something here, but I don't know how long it takes
        conditionOk = true; 

    }, jobWillBeDoneInNMiliseconds);


    // I need to stop right here until
    // stop here until ( 3000 timeout is passed ) or ( conditionOk ==     true )

    timeWas = new Date();

    wait = setInterval(function() {
        if (conditionOk) {
            // Communicate what you were trying to return using globals
            clearInterval(wait);
        }
        if (new Date() - timeWas > 3000) { // Timeout
            // Clear this interval
            clearInterval(wait);
        }
    }, 30);
}

随着一会儿

// this function needs to return a simple string 

function something() { 

    conditionOk = false;

    var jobWillBeDoneInNMiliseconds = Math.floor(Math.random() * 10000);

    timeout = setTimeout(function() {

        // I need to do something here, but I don't know how long it takes
        conditionOk = true; 

    }, jobWillBeDoneInNMiliseconds);


    // I need to stop right here until
    // stop here until ( 3000 timeout is passed ) or ( conditionOk ==     true )

    timeWas = new Date();

    while ((! conditionOk) && (! (new Date() - timeWas > 3000))) { // 3000 = the delay
        // Do nothing
    }
    if (conditionOk) {
        return "returned something";
    }
    else {
        return "returned nothing";
    }
}

您可能还想看看这个问题: JavaScript sleep/wait before continue

希望这可以帮助!

当我在寻找类似的解决方案时,我在浏览器中打开了这个问题。 可能帖子作者不再需要它,但这里有来自非事件循环世界(php、java、python)的其他人。

这是我在阅读 MDN 后得到的: https ://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await https://developer.mozilla.org/en-US/docs/Web /JavaScript/参考/语句/async_function

这两个描述了需要什么。 为此,您将需要一些辅助函数。 它看起来臃肿,但似乎在 JS 中没有其他方法。 虽然完成了工作:)

 // sleep helper function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)) } // func that will check your condition function checkCondition(number) { if (number == 5) return true; else return false; } // helper that will wait and then check the condition // await halts the execution flow until sleep is resolved // this is the part that you need async function waitOneSecondAndCheckCondition(number) { const v = await sleep(500); return checkCondition(number); } // since most likely you want to poll the checkCondition // and not waste all the time waiting // this polls conditon every half a second // and in the end return a simple string // either when condition is met or after three seconds async function waitUntilConditionIsMetOrTimeoutIsPassed() { for (let i = 0; i < 6; i++) { let result = await waitOneSecondAndCheckCondition(i); console.log("i is: " + i + " condition result is: " + result); if (!result) continue; else break; } } waitUntilConditionIsMetOrTimeoutIsPassed();

如果在 3 秒内的某个时间点满足条件,则控制台输出:

i is: 0 condition result is: false
i is: 1 condition result is: false
i is: 2 condition result is: false
i is: 3 condition result is: true
a simple string

发生超时时的控制台输出:

i is: 0 condition result is: false
i is: 1 condition result is: false
i is: 2 condition result is: false
i is: 3 condition result is: false
i is: 4 condition result is: false
i is: 5 condition result is: false
a simple string

希望这对你们所有像我一样的JS新手有帮助:)

如果要等到满足条件:

 main(); async function main() { let foo = 0; // for demo purposes, artificially increment foo setInterval(() => foo++); console.log('Waiting until foo reaches 1337 ...'); await until(() => foo === 1337); console.log('foo === ' + foo); } function until(condition) { return new Promise((resolve) => { const interval = setInterval(() => { if (condition()) { clearInterval(interval); resolve(); } }); }); }

如果你想等到一定时间过去:

 main(); async function main() { console.log('Waiting 2 seconds ...'); await milliseconds(2_000); console.log('Done!'); } function milliseconds(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); }

好的,因为您使用的是ajax ,您可以执行以下操作:

var eventEmitter = new EventEmitter()
eventEmitter.on('myEvent', myFunction)

$.ajax(...).then(function() {
  eventEmitter.emit('myEvent', {state: true})
})

setTimeout(function() { eventEmitter.emit('myEvent', {state: false}), 3000);

function myFunction() {
   //you can do your checks inside here
}

不使用jQuery的 ajax:

var xhr = new XMLHttpRequest();
xhr.open('GET', 'myservice/username?id=some-unique-id');
xhr.onload = function() {
  if (xhr.status === 200) {
    eventEmitter.emit('myEvent', {state: true})
  }
  else {
    alert('Request failed.  Returned status of ' + xhr.status);
  }
};
xhr.send();

对于 Typescript,我修改了 @pbotas 的答案,如下所示:

export const sleepUntil = async (f: () => boolean, timeoutMs: number) => {
  return new Promise((resolve, reject) => {
    const timeWas = new Date();
    const wait = setInterval(function () {
      if (f()) {
        console.log('resolved after', +new Date() - +timeWas, 'ms');
        clearInterval(wait);
        resolve(true);
      } else if (+new Date() - +timeWas > timeoutMs) {
        // Timeout
        console.log('rejected after', +new Date() - +timeWas, 'ms');
        clearInterval(wait);
        reject(false);
      }
    }, 20);
  });
};

请注意,我正在评估一个布尔条件。

调用此函数:

sleepUntil(() => someBoolean, 5000)
 .then(() => {
    // ready
 })
 .catch(() => {
   // timeout
 });

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM