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

JavaScript中等待Parse Library项保存完成解决优先级重复问题

问题现象

对数据项做优先级排序时,编写的循环处理逻辑输出结果不符合预期:

  • 预期优先级序列:[1,2,3,4,5]
  • 实际输出序列:[1,1,2,2,3]
  • 测试验证:在循环中添加alert增加执行延迟后,可以得到正确输出

对应实现的switchPriority异步函数代码如下:

const switchPriority = async function(catId, srcI, destI){
  let indexofCat;
  try {
    for (let i = 0; i < data[0].length; i++) {
      const element = data[0][i];
      if(element.id === catId){
        indexofCat = i;
      }
    } 
    let Item = Parse.Object.extend('Item')
    let itemQuery = new Parse.Query(Item)
    for (let i = (srcI>destI?destI:srcI); i < (srcI>destI?(srcI+1):(destI+1)); i++) {
      let id = data[1][indexofCat][i].id;
      let item = await itemQuery.get(id);
      item.set("priority",i+1);
      await item.save();
    }
  } catch (error) {
    alert(error)
  }
  
}
问题根因

两个问题叠加导致优先级重复:

  1. 本地状态与后端数据不同步:优先级计算完全依赖内存中缓存的data数组,但每次item.save()更新后端数据后,没有同步修改本地data里对应项的优先级和排序位置。如果短时间内多次触发排序(比如拖拽操作的连续事件触发),后续执行的逻辑会读取到旧的data快照,重复计算出相同的优先级值写入后端。
  2. 异步操作没有并发控制:switchPriority是异步函数,如果上一次函数内的所有save操作还没执行完就触发了下一次调用,两个异步流程会交叉执行,互相覆盖写入的优先级值。

加alert后能得到正确结果,本质是弹窗阻塞了JS主线程,既等来了上一批异步保存的完成,也给了本地状态同步更新的时间,不会出现旧数据读入、流程交叉的问题,所以结果正常。

修复方案
  • 每次执行save操作后,立刻同步更新本地data数组中对应项的优先级和排序位置,不要等后端查询返回再更新本地状态,保证所有后续逻辑读取到的都是最新值。
  • 给switchPriority加执行锁,函数执行开始时置锁为占用状态,所有循环内的保存操作全部完成后再释放锁,锁占用期间直接忽略新的排序触发请求,避免多个异步流程并发交叉执行。
  • 优化请求逻辑:循环内不需要每次都调用itemQuery.get(id)拉取最新对象,已知操作项id的前提下,可以直接创建Parse对象实例执行更新,减少网络请求耗时,降低并发冲突的概率。

修改后的核心参考代码:

// 排序操作执行锁
let isSwitching = false;
const switchPriority = async function(catId, srcI, destI){
  // 锁占用时直接返回,避免并发
  if(isSwitching) return;
  isSwitching = true;
  let indexofCat;
  try {
    for (let i = 0; i < data[0].length; i++) {
      const element = data[0][i];
      if(element.id === catId){
        indexofCat = i;
        // 找到目标分类后直接终止循环,减少无效遍历
        break;
      }
    } 
    let Item = Parse.Object.extend('Item')
    const start = srcI>destI?destI:srcI;
    const end = srcI>destI?(srcI+1):(destI+1);
    for (let i = start; i < end; i++) {
      const currentItem = data[1][indexofCat][i];
      const id = currentItem.id;
      // 跳过多余get请求,直接创建对象实例更新
      let item = new Item();
      item.id = id;
      item.set("priority",i+1);
      await item.save();
      // 同步更新本地缓存状态
      currentItem.priority = i+1;
    }
  } catch (error) {
    alert(error)
  } finally {
    // 无论操作成功失败,最终都释放锁
    isSwitching = false;
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 21:00:55