防止ajax重复提交引出的另一个问题

//伪代码如下
function fooClick(){
    $('button').prop('disable',true);
    $.ajax({
        ...
        async:false, //同步
        success: function(){
            $('button').prop('disable',false);
            ...
        },
        error:funciton(){
            $('button').prop('disable',false);
            ...
        }
    })
}

目的比较简单,点击后button变成不可点击,直到http响应完成,变回可以点击。

问题是: 如上代码,当ajax的async属性为false(即同步)时,短时间内快速连续点击3次button(即在第一个ajax还在pending的时候继续点2下button),会依次触发3次ajax请求,当然这3次请求都是等前一个ajax请求响应完成再发起另一次的

当我把ajax的async属性变成true(异步)时候,同样短时间内快速连续点击3次button,只会触发一次ajax请求。(这样的效果是我期望的)

问题是:为什么同步的情况下,click事情似乎被放进一个堆里面?

阅读 2.5k
2 个回答

$('button').prop('disable', false); 引起 repaint

repaintreflow 并不是执行到代码,就立即更新到dom 而是放到一个队列,脚本执行完毕一次执行完毕。

代码错误

//伪代码如下
function fooClick(){
    $('button').prop('disable', true);// 这里true 才是禁止点击
    $.ajax({
        ...
        async:false, //同步
        success: function(){
            $('button').prop('disable', false);// 这里false 解除禁止点击
            ...
        },
        error:funciton(){
            $('button').prop('disable', false);// 这里false 解除禁止点击
            ...
        }
    })
}

同步

  1. 执行 $('button').prop('disable', true); 引起 repaint 不更新 dom 放到dom更新队列。

  2. 继续执行 同一个函数,执行 同步 ajax 。

  3. 同步 ajax 执行完毕,执行 $('button').prop('disable', false); 引起 repaint 不更新 dom 放到dom更新队列。

  4. 整个代码执行完毕。

  5. 执行更新 dom 队列, dom 一次更新成 最后一个结果 也就是 $('button').prop('disable', false)

同步情况下,dom没有更新的情况下(在 第5步 之前) 你快速连续点击,点击几次就执行几次

异步

  1. 执行 $('button').prop('disable', true); 引起 repaint 不更新 dom 放到dom更新队列。

  2. 继续执行 同一个函数,执行 异步 ajax 。

  3. 代码执行完毕 执行更新 dom 队列, dom 更新成 $('button').prop('disable', true);

  4. 异步 callback 执行 $('button').prop('disable', false); 引起 repaint 不更新 dom 放到dom更新队列。

  5. 异步 callback 执行完毕。

  6. 执行更新 dom 队列, dom 更新成 $('button').prop('disable', false)

异步情况下,dom 第一次更新在发出 ajax 请求后就执行了,你的感受来说,就是立即执行了,只能点击一次。

建议

避免仅仅使用 dom 控制多次点击

var _isSubmiting = false;
function fooSubmiting(flag){
    var ret = !!flag;
    $('button').prop('disable', ret);
    _isSubmiting = ret;
}
function fooClick(){
    if (_isSubmiting) {
      return;
    }
    fooSubmiting(true);
    $.ajax({
        ...
        async:false, //同步
        success: function(){
            fooSubmiting(false);
            ...
        },
        error:funciton(){
            fooSubmiting(false);
            ...
        }
    })
}

ajax的目的就是异步加载,如果你要是想同步和点击submit没有什么差别的。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏