Javascript 在$.Deferred.done()中,很快调用

Javascript 在$.Deferred.done()中,很快调用,javascript,jquery,jquery-deferred,Javascript,Jquery,Jquery Deferred,这是一个例子来说明我的问题 $.fn.Heartbeat = function(){ console.log('started'); $.ajax({ url:baseurl.php, . . . success: function(data){ //DO SOME STUFF console.log('end of success'); } } $.when($('.mydiv').Heartbeat()).d

这是一个例子来说明我的问题

$.fn.Heartbeat = function(){
  console.log('started');
  $.ajax({
    url:baseurl.php,
    .
    .
    .
    success: function(data){
      //DO SOME STUFF
      console.log('end of success');
    }
} 

$.when($('.mydiv').Heartbeat()).done(function(){console.log('after done');});
此代码输出:

已启动

完成后

成功结束

虽然我想:

已启动

成功结束

完成后


我的意思是,在Heartbeat完成之后必须执行DONE中的函数,否则它就不能完成

这是一种奇怪的方法,但是首先需要将
Heartbeat
函数添加到jQuery的原型中,以便能够链接它

其次,您需要将ajax函数中的承诺返回到
$。当
时,只有在承诺解析时才会执行
done
回调,如下所示

$.fn.Heartbeat = function () {
    console.log('started');
    return $.ajax({
        url: 'baseurl.php',
        success: function (data) {
            //DO SOME STUFF
            console.log('end of success');
        }
    });
}

$.when($('.mydiv').Heartbeat()).done(function () {
    console.log('after done');
});


要为每个元素发送ajax请求,并在所有请求成功完成后解析承诺,可以执行以下操作

$.fn.Heartbeat = function () {
    console.log('started');

    var def = new Deferred();

    $.when.apply(undefined, 
        $.map(this, function() {
            return $.ajax({
                url: '/echo/html/',
                success: function (data) {
                    //DO SOME STUFF
                    console.log('end of success');
                }
            });
        })
    ).then(def.resolve);

    return def.promise();
}

$('.mydiv').Heartbeat().done(function () {
    console.log('after done');
});
$。when()
不是魔术。它不知道传递给它的某个函数何时完成。相反,你必须给它一个承诺,然后它就会知道这个承诺何时兑现。因为您没有从
Hearbeat()
函数返回承诺,
$.when()
不知道ajax调用何时实际完成,因此它将其视为同步事件

以下是一种更简单的方法:

var Heartbeat = function(){
  console.log('started');
  return $.ajax({
    url:baseurl.php,
    // other args
  }).then(function(data) {
        //DO SOME STUFF
        console.log('end of success');
  });
} 

Heartbeat().done(function(){
   console.log('after done');
});
变化:

  • 您必须从Heartbeat返回承诺,以便
    .done()
    可以等待它
  • 无需对单个承诺使用
    $.when()
    ,只需对该承诺使用
    .then()
  • Heartbeat
    是一个常规函数(不是jQuery方法),因此可以将其作为常规函数调用。由于该函数没有以任何方式使用jQuery对象,因此我认为没有任何理由将其作为jQuery方法
  • 将成功处理程序切换为使用
    。然后()
    ,因为您正在使用承诺
  • 将柱撑和支撑固定在合法位置

  • 抱歉,在我的代码中,我已经有了$.fn.Heartbeat,但是即使我返回promise@Ferex它确实有效,adeneo的代码与您在问题中发布的代码有一个词的不同,并且有效。我想这对你不起作用的原因是xhr失败了,它只打印出
    start
    ,或者你正在使用你没有发布的代码,所以没有人能够猜测出哪里出了问题,因为你没有发布代码,也没有在评论中说出哪里出了问题
    它不起作用
    不是描述问题的方法。而且您不需要
    $.when()
    <代码>$('.mydiv').heartbeat().done(…)将完成此任务。(注意-我将“H”改为小写)。它成功了,我用done而不是then测试了它。然而,我不明白这里的重要教训。如果我不使用return怎么办?Heartbeat.done()不应该等待Heartbeat()完成吗?@Ferex done也可以,adeneo的答案也可以。如果复制代码,将其粘贴到控制台中,将“baseurl.php”更改为“”,然后在此页面上运行,您会发现它工作得很好。为什么你认为心跳应该返回一些东西?您需要将某个内容传递到
    where
    ,或者对某个内容调用
    done
    。如果Heartbeat没有返回您试图调用的内容,则在
    未定义的
    上完成或将udefined传递到何处。很抱歉我的无知,但不是每个函数都返回内容吗??这就是我所想的:如果没有返回表达式,函数在完成时会返回true,而在其他情况下返回false。否。任何没有显式返回的函数都将返回
    undefined
    @Ferex-没有显式返回语句的函数返回
    undefined
    ,因此您将
    undefined
    传递给
    $。when()
    $.when()
    等待传递给它的承诺完成。如果您不向它传递任何承诺,它会认为一切都必须已经完成,因此它会立即执行
    .done()
    回调,而不是等待ajax调用完成。