【问题标题】:jQuery Deferred/promise not working as expectedjQuery Deferred/promise 没有按预期工作
【发布时间】:2017-06-21 07:18:30
【问题描述】:

好的,我已经阅读了 1,000,000 多篇关于 jQuery 延迟和/或承诺的文章,但我仍然遇到了一些问题。

functionOne() {
    var deferred = $.Deferred();

    var request = $.ajax({
        url: 'http://example.com/mypath/etc'
    });

    request.done(function(data) {

        // TODO: I've got stuff here that takes a while.

        deferred.resolve();
    });

    return deferred.promise();
}

functionTwo() {
    // Something that depends on the others being finished.
}

$.when(
    functionOne(), 
    anotherLongRunningFunctionWithAjax())
 .then(
    functionTwo()
);

在“then”开始之前,我需要“when”中的任何函数来完全完成(.ajax done)。然而,promise 立即返回(如预期的那样),但 functionTwo 启动,即使 functionOne 没有调用“done”。

我确信这是对延迟调用和调用链的根本误解。

编辑:

function functionOne() {
    console.log('functionOne called');

    var request = $.ajax({
        url: 'http://example.com/mypath/etc'
    });

    request.done(function(data) {
        console.log('Starting Done.');

        setTimeout(function () {
            console.log('Done finished.');
        }, 5000);
    });

    console.log('Returning promise.');
    return request;
}

function functionTwo() {
    console.log('functionTwo called');
}

$.when(functionOne()).then(functionTwo());

在控制台中给我这个:

functionOne called
Returning promise.
functionTwo called (should be called after Done is finished.)
Starting Done.
Done finished.

【问题讨论】:

  • var deferred = $.Deferred(); 不必要,你已经从 $.ajax 获得了一个。用 .then 将其链接起来。
  • 您的逻辑应该可以正常工作,我猜// TODO: 部分实际上有代码并且没有正确延迟 .resolve() 调用。
  • @KevinB 老实说,我先尝试了没有额外的 $.Deferred,但我也无法让它工作。我确定我错过了一些简单的东西。
  • 更新后的新代码不会在函数 1 的 setTimeout 完成时延迟函数 2,这是设计使然。对于该功能,您必须使用 .then 而不是 .done 并创建一个新的 Promise 以返回 .then ,它会在 setTimeout 完成时解决。此外,单个 Promise 不需要 $.when,但它也不一定有害。
  • @KevinB 但是无论我使用的是 setTimeout 还是其他东西,至少不会出现“开始完成”吗?我实际上并没有使用 setTimeout,而是加载了一个下拉列表。其实可以完全注释掉setTimeout,“Starting done”还是最后出现的。

标签: javascript jquery


【解决方案1】:

在您编辑的代码中,有两个问题:

  1. functionOne 中的计时器在 request 解决后启动,但您返回 request。所以无论计时器发生什么......它与返回的承诺无关,当时已经解决了。

  2. 您立即调用 functionTwo,而不是传递 $.when 回调的函数引用

这是工作代码:

function functionOne() {
    console.log('functionOne called');
    console.log('Returning promise.');
    return $.ajax({
        url: 'https://jsonplaceholder.typicode.com/posts/1'
    }).then(function(data) {
        console.log('Starting Done.');
        var dfd = $.Deferred();
        setTimeout(function () {
            console.log('Done finished.');
            dfd.resolve(data); // indicate when you are done
        }, 2000); // 2 seconds will do ;-)
        return dfd.promise(); // you need to return a promise again
    });
}

function functionTwo() {
    console.log('functionTwo called');
}

// don't call functionTwo immediately, leave that to the promise to do:
$.when(functionOne()).then(functionTwo);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

【讨论】:

  • 另外,供将来参考(供我自己参考):如果我在“then”中为 functionTwo 添加括号(例如 .then(function())),该函数仍将立即触发。因此,如果 functionTwo 中需要参数,请创建一个包含函数指针的 var。例如var f2 = function() { functionTwo(param); } 并将指针传递给“.then(f2)”。或者,.then(function() { functionTwo(param); });
  • 添加参数也可以使用bind:.then(functionTwo.bind(null, param))
【解决方案2】:

你是using an anti-pattern,因为$.ajax 本身会返回一个承诺

做事

functionOne() {

    var request = $.ajax({
        url: 'http://example.com/mypath/etc'
    });

    request.done(function(data) {
        // TODO: I've got stuff here that takes a while.       
    });

    return request
}

【讨论】:

  • 不知道是什么“我这里有东西需要一段时间” 是不是很难提供更多帮助
  • 我的提问被否决了?我问是因为我不明白。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-03-17
  • 2019-07-13
  • 2012-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多