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

jQuery中如何让$.done()回调触发两次及异步请求回调问题

解决你的jQuery异步回调多次触发问题

首先,先明确一个关键知识点:jQuery的Deferred对象的done()回调只会在对象被resolve()(完成)时触发一次。如果想要同一个回调被触发多次,你需要用到progress()回调,配合deferred.notify()来发送多次更新通知。

针对你的代码场景,我们一步步来修改:

1. 修复startAsyncRequest的返回值问题

你当前的startAsyncRequest函数没有返回任何Deferred对象,导致Part A中的$.when()其实是在处理一个undefined值,会立即执行一次done()回调,后续的异步结果完全无法触发它。所以首先要让这个函数返回一个可控的Deferred:

jQuery.extend({ 
    startAsyncRequest: function(arg){ 
        // 创建一个Deferred对象用于对外传递状态
        var deferred = $.Deferred();
        console.log(arg); 
        
        $.when(makeAjaxRequest(arg)).done(function(result){ 
            var taskid = result.taskid; 
            var taskurl = "someurl" + taskid; 

            // 假设这里的startProgressBar包含轮询taskurl的逻辑
            // 我们需要在每次轮询到结果时通知外部
            function pollTaskStatus() {
                $.get(taskurl).done(function(pollResult) {
                    // 每次拿到轮询结果,用notify发送给外部
                    deferred.notify(pollResult);

                    if (pollResult.hasOwnProperty("responseJSON") && pollResult.responseJSON.status === "completed") {
                        // 任务完成时,resolve这个Deferred,表示最终完成
                        deferred.resolve(pollResult);
                    } else {
                        // 未完成则继续轮询
                        setTimeout(pollTaskStatus, 1000);
                    }
                });
            }

            pollTaskStatus();
        });

        // 返回Deferred的promise,避免外部直接修改状态
        return deferred.promise();
    }
});

2. 修改Part A的回调绑定逻辑

现在startAsyncRequest返回了一个支持多次通知的Promise,你可以用progress()来监听每次的结果更新,用done()来监听最终完成的状态:

// 先获取promise对象
var requestPromise = $.startAsyncRequest(arg);

// 抽离重复执行的逻辑为单独函数
function handleResult(result) {
    console.log(result);
    if (result.hasOwnProperty("responseJSON")){
        console.log("build frontend table using completed task"); 
    }
}

// 绑定progress回调,每次notify都会触发
requestPromise.progress(handleResult);
// 绑定done回调,最终完成时触发(可选,如果你需要在完成时额外处理)
requestPromise.done(handleResult);

如果你确实希望用$.when()的方式(虽然这里直接用返回的promise更简洁),也可以这样写:

$.when($.startAsyncRequest(arg))
    .progress(function(result) {
        console.log(result);
        if (result.hasOwnProperty("responseJSON")){
            console.log("build frontend table using completed task"); 
        }
    })
    .done(function(result) {
        // 可选:任务最终完成时的额外处理
        console.log("任务完全结束", result);
    });

为什么不直接用done()触发多次?

因为jQuery的Deferred设计是一次性状态:一旦被resolve()或reject(),状态就固定了,不会再触发对应的done()或fail()回调。而progress()是专门用于传递中间更新的,可以被多次触发,完全匹配你“每次有结果返回都执行回调”的需求。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:41:43