【问题标题】:JavaScript wait for async functions in while loopJavaScript 在 while 循环中等待异步函数
【发布时间】:2018-09-25 00:13:23
【问题描述】:

我目前有5个功能;每个人都使用setInterval 等待元素加载,然后在元素可用时单击该元素,从而进入下一个网页。这些函数也发生在while 循环内。这些函数一个接一个地执行是非常重要的,while 循环在再次循环之前等待所有函数完成。由于函数是异步的,循环将在任何函数加载之前运行x 次。

我正在尝试做的示例:

function one () {
    var checkForItem = setInterval(function () {
        if ($('#element').length) {
            $('#element').click();
            clearInterval(checkForItem);
        }
    }, 100);
}

想象一下其中的 5 个函数(onetwothreefourfive),所有函数都使用相同的格式,使用 setInterval 和以下 while 循环:

var x = 0, y = 10;

while (x < y){
    one();
    two();
    three();
    four();
    five();
    x++
}

在循环继续之前,我将如何确保所有功能一个接一个地发生?

注意:我尝试过使用 Promise,但由于函数是异步的,循环在函数完成之前仍会继续。

【问题讨论】:

  • 正确缩进代码会使其更具可读性。
  • 如果没有修改函数的行为,执行循环的原因是什么?通过执行这些功能一次就可以了
  • @JoseAPL 随着 x 的增加,这些函数的行为会有所不同。以上只是我正在尝试做的一个简单示例。这些函数将单击不同的按钮并根据数组和 x 值抓取一些内容。
  • 您的每个函数都需要返回一个承诺,这样您就可以使用Promise.all 等待所有调用或者,您可以使用github.com/angular/zone.js,它通过修补低级别调用来跟踪异步JS 代码,例如setTimeout
  • each one uses setInterval to wait for an element to load - 听起来很老套

标签: javascript asynchronous while-loop promise


【解决方案1】:

async/await 语法与承诺一起使用:

function delay(t) {
    return new Promise(resolve => setTimeout(resolve, t));
}
async function one() {
    while (!$('#element').length) {
        await delay(100);
    }
    $('#element').click();
}

async function main() {
    for (var x = 0; x < 10; x++) {
        await one();
        await two();
        await three();
        await four();
        await five();
    }
}

【讨论】:

    【解决方案2】:

    在数组中定义选择器,在区间内逐步迭代数组,直到到达数组的末尾:

    const initialSelectorsToFind = ['#element1', '#element2', '#element3']; // add more as desired
    const elementSelectorsToFind = Array.from({ length: 10 })
      .reduce(arrSoFar => [...arrSoFar, ...initialSelectorsToFind], []);
    let elementIndexToFind = 0;
    function tryClick(){
      const elementToFind = $(elementSelectorsToFind[elementIndexToFind]);
      if (elementToFind.length) {
        elementToFind.click();
        elementIndexToFind++;
        if (elementIndexToFind === elementSelectorsToFind.length) {
          clearInterval(tryClickInterval);
        }
      }
    }
    const tryClickInterval = setInterval(tryClick, 100);
    

    但是如果你想在元素被添加到 DOM 时触发一个函数(比如点击一个元素),那么最好使用触发 when 的东西添加发生,例如创建者函数中的回调,或 MutationObserver

    【讨论】:

    • 首先,我要感谢你,因为你昨晚也帮助了我!这个解决方案对我不起作用,因为我基本上需要 elementSelectorsToFind 被遍历 x 次,因此需要一个循环。
    • 查看编辑:您可以首先使用.reduce 重复初始选择器任意次数
    【解决方案3】:

    尝试使用异步等待包装承诺:

    async function one (){
          await (new Promise(function(reolve, reject){
             var checkForItem = setInterval(function () {
               if ($('#element').length) {
                  $('#element').click();
                  clearInterval(checkForItem);
                  resolve();
                }
             }, 100);
          }));
    }
    
    //And then in your while loop:
    while (x < y){
        await one();
        await two();
        ...
        x++
    }
    

    注意:您的 while 循环也必须包含在异步函数中。

    【讨论】:

    • 什么都不做 .then() 是怎么回事?此外,在您的代码中根本不清楚,await one() 等必须在 async 函数中执行
    猜你喜欢
    • 2020-03-27
    • 2020-04-20
    • 2019-07-02
    • 2021-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-05
    • 2019-07-04
    相关资源
    最近更新 更多