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

二次加载弹窗下拉切换出现Cannot read property 'done' of undefined报错

问题原因

核心是事件重复绑定+全局请求状态变量污染两个问题共同导致:

  • 每次加载弹窗时你都给下拉选择框重新绑定了一次change事件,但关闭弹窗移除DOM时没有解绑之前绑定的事件,第二次打开弹窗后切换下拉会同时触发两次绑定的回调函数,先后两次调用makeRequest
  • 你封装的makeRequest里用了全局/外层作用域的inProgressRequest变量做请求防重:第一次回调调用makeRequest时会把inProgressRequest设为true,紧接着触发的第二次回调调用makeRequest时,检测到inProgressRequest为true就会走到else分支,没有返回Promise对象,你在调用makeRequest后链式调用的.done()就会抛出“Cannot read property 'done' of undefined”错误。
解决方案

你可以根据自己的业务场景选任意一种方案,也可以组合使用提升兼容性:

  • 方案1:绑定事件前先解绑原有事件
    每次给下拉框绑定change事件前,先移除之前绑定的事件,避免重复触发:
    // 弹窗加载完成后绑定事件的代码修改为
    $('#你的下拉框ID').off('change').on('change', function() {
      makeRequest(/* 你的请求参数 */).done(function(res) {
        // 原有业务逻辑
      })
    })
    
  • 方案2:使用事件委托仅绑定一次
    不需要每次加载弹窗都绑定事件,直接在页面初始化时给页面固定容器做事件委托,一次绑定就可以适配后续动态加载的下拉元素:
    // 页面初始化时仅执行一次即可
    $('body').on('change', '#弹窗内下拉框的ID', function() {
      makeRequest(/* 你的请求参数 */).done(function(res) {
        // 原有业务逻辑
      })
    })
    
  • 方案3:修复makeRequest的返回值兼容
    即使命中防重逻辑,也返回一个已完成的Promise对象,避免调用.done时报错:
    function makeRequest(/* 你的入参 */) {
      if (inProgressRequest) {
        // 返回已经resolve的Deferred对象,不会触发链式调用报错
        return $.Deferred().resolve().promise()
      }
      inProgressRequest = true
      return $.ajax(/* 你的请求配置 */).always(function() {
        inProgressRequest = false
      })
    }
    
  • 方案4:替换全局防重逻辑
    如果makeRequest是多场景共用的工具函数,不要用全局的inProgressRequest,改用请求URL+参数的哈希值做Key,用Map存储不同请求的防重状态,避免不同业务的请求互相干扰。

内容的提问来源于stack exchange,提问作者Tóth András

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.12 03:18:04