You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue.js实现快速排序可视化遇async/await问题求助

解决Vue.js快速排序可视化中的async/await递归问题

嘿,我完全懂你遇到的困扰!你推测递归里的async/await是问题根源,这个判断太准啦~咱们一步步拆解问题,然后把它修好。

问题核心分析

你的quickSort是同步函数,但它调用的partition却是异步函数(带async/await)。这就导致:

  • quickSort不会等partition完成分区和交换操作,就直接执行后面的递归调用,整个排序的逻辑顺序彻底乱套了;
  • sortArray里直接把quickSort的返回值赋值给numArray,但quickSort同步执行时,partition里的异步交换还没开始,所以numArray一开始还是原数组,后续异步操作才慢慢修改数组,导致UI更新和排序节奏完全不匹配。

修复方案

我们只需要把递归的quickSort也改成异步函数,并用await等待每一步异步操作完成,让排序逻辑按顺序执行:

1. 修改quickSort为异步函数

async function quickSort(arr, left, right) {
  var len = arr.length, pivot, partitionIndex;
  if (left < right) {
    pivot = right;
    // 等待分区操作完成,拿到正确的partitionIndex
    partitionIndex = await partition(arr, pivot, left, right);
    // 等待左右子数组的排序完成,保证顺序正确
    await quickSort(arr, left, partitionIndex - 1);
    await quickSort(arr, partitionIndex + 1, right);
  }
  return arr;
}

2. 修改sortArray方法为异步函数

async sortArray: function(event) {
  // 等待整个排序过程完成
  await quickSort(this.numArray, 0, this.numArray.length - 1);
  console.log(this.numArray);
}

3. (可选优化)避免函数名冲突

你的Vue组件方法shuffleArray和全局函数shuffleArray同名了,虽然能工作,但容易混淆,建议把全局函数改名:

// 全局函数改名
function shuffle(arr) {
  var currentIndex = arr.length, temporaryValue, randomIndex;
  while (0 !== currentIndex) {
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;
    temporaryValue = arr[currentIndex];
    Vue.set(arr, currentIndex, arr[randomIndex]);
    Vue.set(arr, randomIndex, temporaryValue);
  }
  return arr;
}

// 组件方法里调用改名后的函数
shuffleArray: function(event) {
  var tempArray = shuffle([...this.numArray]); // 复制数组再打乱,避免修改原数组时的响应式问题
  this.numArray = tempArray;
}

完整修复后的代码

这里把所有修改整合到一起,你可以直接用:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
  <style>
    body {
      font-family: sans-serif;
      font-size: 12px;
      font-weight: 700;
    }
    .container {
      display: block;
      clear: both;
      overflow: hidden;
    }
    .el {
      border: 1px solid lightgray;
      float: left;
      width: 2%;
      text-align: center;
      padding: 10px 0;
      width: 25px;
      margin: 0 2px;
    }
    .btn {
      display: block;
      margin-top: 20px;
      clear: both;
      border: 2px solid orange;
      text-align: center;
      padding-top: 10px;
      padding-bottom: 10px;
      cursor: pointer;
      text-decoration: none;
      color: black;
    }
  </style>
</head>
<body>
  <div id="app">
    <div class="container" id="scene1">
      <div class="el" v-for="item in numArray">{{ item }}</div>
    </div>
    <a href="#" v-on:click.prevent="fillArray" class="btn">Fill array</a>
    <a href="#" v-on:click.prevent="shuffleArray" class="btn">Shuffle array</a>
    <a href="#" v-on:click.prevent="sortArray" class="btn">Sort array</a>
  </div>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
  <script>
    // noprotect
    var app = new Vue({
      el: '#app',
      data: {
        numArray: []
      },
      methods: {
        fillArray: function(event) {
          this.numArray = []; // 先清空,避免重复填充
          for (var i = 0; i<30; i++) {
            this.numArray.push(i);
          }
        },
        shuffleArray: function(event) {
          var tempArray = shuffle([...this.numArray]); // 复制数组再打乱,避免修改原数组时的响应式问题
          this.numArray = tempArray;
        },
        async sortArray: function(event) {
          await quickSort(this.numArray, 0, this.numArray.length - 1);
          console.log(this.numArray);
        }
      }
    })
    Vue.config.devtools = false;

    function sleep(ms = 0) {
      return new Promise(r => setTimeout(r, ms));
    };

    function getRandomInt(min, max) {
      return Math.floor(Math.random() * (max - min + 1)) + min;
    }

    function shuffle(arr) {
      var currentIndex = arr.length, temporaryValue, randomIndex;
      while (0 !== currentIndex) {
        randomIndex = Math.floor(Math.random() * currentIndex);
        currentIndex -= 1;
        temporaryValue = arr[currentIndex];
        Vue.set(arr, currentIndex, arr[randomIndex]);
        Vue.set(arr, randomIndex, temporaryValue);
      }
      return arr;
    }

    async function quickSort(arr, left, right) {
      var len = arr.length, pivot, partitionIndex;
      if (left < right) {
        pivot = right;
        partitionIndex = await partition(arr, pivot, left, right);
        await quickSort(arr, left, partitionIndex - 1);
        await quickSort(arr, partitionIndex + 1, right);
      }
      return arr;
    }

    async function partition(arr, pivot, left, right) {
      var pivotValue = arr[pivot], partitionIndex = left;
      for (var i = left; i < right; i++) {
        if (arr[i] < pivotValue) {
          swap(arr, i, partitionIndex);
          await sleep(100);
          partitionIndex++;
        }
      }
      swap(arr, right, partitionIndex);
      await sleep(100);
      return partitionIndex;
    }

    function swap(arr, i, j) {
      var temporaryValue = arr[i];
      Vue.set(arr, i, arr[j]);
      Vue.set(arr, j, temporaryValue);
    }
  </script>
</body>
</html>

为什么这样改能解决问题?

  • 把quickSort改成异步函数后,每一步的partition和递归调用都需要await等待完成,这样排序逻辑就会按正确的顺序执行:先完成当前分区的所有交换,再递归排序左右子数组;
  • sortArray用await等待整个排序过程结束,确保UI能实时跟随每一步交换更新,不会出现逻辑和UI脱节的情况。

内容的提问来源于stack exchange,提问作者Maxim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:57:24