jQuery Deferred/promise 没有按预期工作
Posted
技术标签:
【中文标题】jQuery Deferred/promise 没有按预期工作【英文标题】:jQuery Deferred/promise not working as expected 【发布时间】: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”还是最后出现的。
【参考方案1】:
在您编辑的代码中,有两个问题:
functionOne 中的计时器在 request 解决后启动,但您返回 request。所以无论计时器发生什么......它与返回的承诺无关,当时已经解决了。
您立即调用 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
【讨论】:
不知道是什么“我这里有东西需要一段时间” 是不是很难提供更多帮助 我的提问被否决了?我问是因为我不明白。以上是关于jQuery Deferred/promise 没有按预期工作的主要内容,如果未能解决你的问题,请参考以下文章
通过 ES6 Promise 和 jQuery Deferred 的异同学习 Promise
jQuery Deferred/promise 没有按预期工作