JavaScript setTimeout执行顺序

时间:2019-12-03 19:57:32

标签: javascript asynchronous

我正在构建一个排序算法可视化程序,它是https://www.cs.usfca.edu/~galles/visualization/ComparisonSort.html的简化版本。如果没有setTimeout函数,则数组将按预期对自身进行排序,并且条形图的顺序正确。但是我想使它像该示例那样具有动画效果,但是在添加setTimeout函数之后,我得到了想要的效果,但是它发生的顺序混乱并且排序错误。我知道超时功能是在主线程之后执行的,但是我不明白为什么这是个问题。间隔为0,它是否仍应正确对数组排序?据我了解,setTimeout函数将全部以相同的顺序运行。

我试图为两个setTimeOuts设置不同的时间间隔,但是即使在0时也会发生乱序,并且数组排序不正确。对于上下文,updateSlowPointer和updateFastPointer所做的所有操作都是突出显示我们正在查看的第j和j + 1个小节。交换,交换两个小节,仅需交换CSS类。

let bubbleSort = (inputArr) => {
let len = inputArr.length;
for (let i = 0; i < len; i++) {
    for (let j = 0; j < len; j++) {
        setTimeout(() => {
            updateSlowPointer(inputArr[j], inputArr[j - 1]);
            updateFastPointer(inputArr[j + 1]);
        }, 0); 

        if (inputArr[j] > inputArr[j + 1]) {
            setTimeout(() => {
                swap(inputArr[j], inputArr[j + 1]);
            }, 0);

            let tmp = inputArr[j];
            inputArr[j] = inputArr[j + 1];
            inputArr[j + 1] = tmp;
        }
    }
}
    return inputArr;
};

1 个答案:

答案 0 :(得分:0)

获取循环和异步权很复杂。但是我们有一个正确的工具:async函数!然后,您可以轻松await循环。或者,如果您希望能够逐步运行算法 (我认为您希望这样做),生成器函数可能是您选择的工具:

  function* bubbleSort(inputArr) {
    let len = inputArr.length;
    for (let i = 0; i < len; i++) {
      for (let j = 0; j < len; j++) {
        updateSlowPointer(inputArr[j], inputArr[j - 1]);
        updateFastPointer(inputArr[j + 1]);
      }

      if (inputArr[j] > inputArr[j + 1]) {
        swap(inputArr[j], inputArr[j + 1]);
      }

      let tmp = inputArr[j];
      inputArr[j] = inputArr[j + 1];
      inputArr[j + 1] = tmp;

       yield inputArr; // < let other code step in here
   }
   return inputArr;
 }

然后,您可以使用async function逐步执行生成器:

 const timer = ms => new Promise(res => setTimeout(res, ms));

 (async function() {
     let stepper = bubbleSort([1, 3, 2]), done = false;
     while(!done) {
       ({ done, value }) = stepper.next();
       // visualization here
       console.log(value);
       await timer(1000);
     }
  })();