简体   繁体   English

Javascript 等待循环完成

[英]Javascript wait for loop to finish

I would like to wait until a for loop is finished to continue with my function.我想等到 for 循环完成后再继续我的 function。 I can't seem to get it to work.我似乎无法让它工作。 Hello is always logged before the for loop finishes. Hello 总是在 for 循环结束之前被记录。 Why is this, and what would be a way to run only when the for loop has finished.为什么会这样,以及只有在 for 循环完成后才能运行的方法。 I need to wait for the for loop to finish before continuing within the function, but outside the for loop.我需要等待 for 循环完成,然后在 function 中继续,但在 for 循环之外。

For the people that keep closing this question, this is different.对于一直关闭这个问题的人来说,这是不同的。 I want to know how to wait until a for loop is finished, and then execute code.我想知道如何等到 for 循环完成,然后执行代码。 Not set timeouts within the for loop.未在 for 循环中设置超时。 Thanks.谢谢。

function doMergeAnimations(animations){
    for (let i = 0; i < animations.length; i++) {
        const arrayBars = document.getElementsByClassName('array-bar');
        const isColorChange = i % 3 !== 2;
        if (isColorChange) {
            const [barOneIdx, barTwoIdx] = animations[i];
            const barOneStyle = arrayBars[barOneIdx].style;
            const barTwoStyle = arrayBars[barTwoIdx].style;
            const color = i % 3 === 0 ? INITCOLOR : SWAPCOLOR;
            setTimeout(() => {
            barOneStyle.backgroundColor = color;
            barTwoStyle.backgroundColor = color;
            }, i * animationSpeed);
        } else {
            setTimeout(() => {
            const [barOneIdx, newHeight] = animations[i];
            const barOneStyle = arrayBars[barOneIdx].style;
            barOneStyle.height = `${newHeight}px`;
            }, i * animationSpeed);
        }
    }
    console.log("Hello")
}

If the actual goal here is to trigger a series of events over time then you can't use a for loop to structure the execution, that doesn't work with asynchronous events.如果这里的实际目标是随着时间的推移触发一系列事件,那么您不能使用for循环来构造执行,这不适用于异步事件。 You must restructure it:你必须重组它:

function doMergeAnimations(animations){
    let events = [ ];
    for (let i = 0; i < animations.length; i++) {
        const arrayBars = document.getElementsByClassName('array-bar');
        const isColorChange = i % 3 !== 2;
        if (isColorChange) {
            const [barOneIdx, barTwoIdx] = animations[i];
            const barOneStyle = arrayBars[barOneIdx].style;
            const barTwoStyle = arrayBars[barTwoIdx].style;
            const color = i % 3 === 0 ? INITCOLOR : SWAPCOLOR;
            events.push(() => {
            barOneStyle.backgroundColor = color;
            barTwoStyle.backgroundColor = color;
            });
        } else {
            events.push(() => {
            const [barOneIdx, newHeight] = animations[i];
            const barOneStyle = arrayBars[barOneIdx].style;
            barOneStyle.height = `${newHeight}px`;
            });
        }
    }

    let timer = setInterval(() => {
        let fn;

        if (fn = events.shift()) {
          fn();
        }
        else {
          clearInterval(timer);
        }
    }, animationSpeed);

    console.log("Hello");
}

As in this quick demo:就像在这个快速演示中一样:

 function arrayPopper(array, delay) { let events = [ ]; array.forEach(e => { events.push(() => console.log(e)); }) let timer = setInterval(() => { let fn; if (fn = events.shift()) { fn(); } else { clearInterval(timer); } }, delay); events.push(() => console.log("Hello")); } arrayPopper([ 1, 2, 3, 4, 5, 6, 'done' ], 500);

You can even easily Promisify this by adding:您甚至可以通过添加以下内容轻松地 Promisify:

async function doMergeAnimations(animations) {
  return new Promise((resolve, _reject) => {
    let events = [ ];

    // Same code...

    events.push(resolve);
  });
}

Which means you can now do:这意味着您现在可以执行以下操作:

// Chained promise
doMergeAnimations(...).then(() => console.log('Done!'));

// async function
await doMergeAnimations(...);
console.log('Done!');

The problem isn't the loop, the problem is what you're doing inside the loop.问题不在于循环,问题在于您循环中所做的事情。 You're invoking asynchronous operations with setTimeout , which all happen later.您正在使用setTimeout调用异步操作,这一切都在以后发生。 If you want to wait for those to finish then you probably want to wrap setTimeout in a Promise and then await it.如果您想等待这些完成,那么您可能希望将setTimeout包装在Promise中,然后等待它。

You can wrap it with something like:你可以用类似的东西包装它:

const setAwaitableTimeout = async (func, delay) =>
  new Promise((resolve) => setTimeout(() => {
    func();
    resolve();
  }), delay);

Then you can make your function async and use this instead of setTimeout .然后你可以让你的 function async并使用它而不是setTimeout Which has the added bonus that you don't need to multiply by i in your delays to mimic the awaiting behavior:哪个有额外的好处,您不需要在延迟中乘以i来模仿等待行为:

async function doMergeAnimations(animations) {
  for (let i = 0; i < animations.length; i++) {
    // existing code, then...
    await setAwaitableTimeout(() => {
      barOneStyle.backgroundColor = color;
      barTwoStyle.backgroundColor = color;
    }, animationSpeed);
    // the rest of your code
  }
  console.log("Hello");
}

If you wrap the setTimeouts() in promises you can control the outcome.如果您将setTimeouts()包装在 Promise 中,您可以控制结果。

Here each animation is placed inside a Promise object and that promise is pushed into an array of Promises.在这里,每个 animation 都放置在 Promise object 内,并且 ZB321DE3BDC299EC807E9F795D7Dmises9DEEBZ 被推入 Pro 数组Each setTimeout() then calls resolve() at the completion of the animation.每个setTimeout()然后在 animation 完成时调用resolve()

Once the loop has completed, Promise.all() is used to wait for the completion of each Promise in the array.循环完成后,使用Promise.all()等待阵列中每个 Promise 完成。 Finally, inside the .then() of the Promise is when the "loop is finished" (conceptually).最后,在 Promise 的 .then .then()内部是“循环完成”(概念上)。

function doMergeAnimations(animations) {
  const animPromises = [];
  for (let i = 0; i < animations.length; i++) {
    const arrayBars = document.getElementsByClassName('array-bar');
    const isColorChange = i % 3 !== 2;
    if (isColorChange) {
      const [barOneIdx, barTwoIdx] = animations[i];
      const barOneStyle = arrayBars[barOneIdx].style;
      const barTwoStyle = arrayBars[barTwoIdx].style;
      const color = i % 3 === 0 ? INITCOLOR : SWAPCOLOR;
      animPromises.push(new Promise(resolve => {
          setTimeout(() => {
            barOneStyle.backgroundColor = color;
            barTwoStyle.backgroundColor = color;
            resolve();
          }, i * animationSpeed)
        });
      }
      else {
        animPromises.push(new Promise(resolve => {
            setTimeout(() => {
              const [barOneIdx, newHeight] = animations[i];
              const barOneStyle = arrayBars[barOneIdx].style;
              barOneStyle.height = `${newHeight}px`;
              resolve();
            }, i * animationSpeed)
          });
        }
      }
      Promise.all(animPromises).then(() => console.log("Hello"));
    }

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

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