嵌套异步jquery承诺

我写了一个小程序来帮助我理解如何在jquery中进行嵌套异步promise。

我想按顺序调用两个任务。 第一个任务有两个也按顺序调用的子任务。 就这样。

虽然这有效,但我怀疑这是否是使用承诺的最佳方式。 必须为每个任务创建一个新的延迟感觉就像代码闻到我。 例如,传递一个延迟对象并仅使用它会更好吗? 谢谢!

doTasks().then(function(arg) { console.log(arg) }) function doTasks() { var d = $.Deferred(); task1().then(function(arg) { console.log(arg) task2().then(function(arg) { console.log(arg) d.resolve('all tasks are done') }) }) return d.promise(); } function task1() { var d = $.Deferred(); console.log("starting task1...") setTimeout(function() { task1A().then(function() { task1B().then(function() { d.resolve('task1 is done') }) }) }, 10); return d.promise(); } function task1A() { var d = $.Deferred(); console.log("starting task1A...") setTimeout(function() { console.log(" resolving task1A...") d.resolve(); }, 1000); return d.promise(); } function task1B() { var d = $.Deferred(); console.log("starting task1B...") setTimeout(function() { console.log(" resolving task1B...") d.resolve(); }, 1000); return d.promise(); } function task2() { var d = $.Deferred(); console.log("starting task2...") setTimeout(function() { d.resolve('task2 is done'); }, 1000); return d.promise() } 

是的,创造许多不必要的延期是有点臭。

您不需要为ajax操作创建任何延迟。 如果从.then()处理程序中返回一个promise,它将自动链接到前一个promise(从而对它进行排序),并且所有jquery ajax调用都已返回promises。 因此,您无需为ajax操作创建任何自己的承诺。 并且,您可以链接而不是嵌套以便对操作进行排序。

实际上,当您不需要时创建延迟或承诺被称为承诺反模式 。 您希望使用并返回已创建的承诺,而不是创建新承诺。 并且,在可能的情况下,您希望链接您的承诺而不是嵌套。

以下是如何在runnable片段中执行此操作而不创建单个延迟,除了在promise中包装setTimeout()地方。 显然,如果你为它们创建了一个可重用的函数,你可以为你的所有任务使用更少的代码,但是我假设这些只是真正的异步操作的占位符,所以我将它们保留原样(除了使用共享delay()函数)。

 doTasks().then(function(arg) { console.log("everything done"); }) function doTasks() { return task1().then(function(arg) { console.log(arg); return task2().then(function(arg) { console.log(arg) return arg; }) }) } // make promise version of setTimeout() in one central place // that can then be used elsewhere function delay(t) { return $.Deferred(function(def) { setTimeout(function() { def.resolve(); }, t); }).promise(); } function task1() { console.log("starting task1...") return delay(10).then(function() { return task1A(); }).then(function() { return task1B(); }); } function task1A() { console.log("starting task1A...") return delay(1000).then(function() { console.log(" resolving task1A...") return "done task1A"; }); } function task1B() { console.log("starting task1B...") return delay(1000).then(function() { console.log(" resolving task1B...") return "done task1B"; }); } function task2() { console.log("starting task2...") return delay(1000).then(function() { console.log(" task2 is done") return "done task2"; }); } 
  

你不应该嵌套你的承诺。 这个想法是你链接它们,通过在第一个then回调中返回一个值, then链接到下一个, then在它自己的回调中将执行下一步,等等。

当您在多个地方使用计时器来解决承诺时,您可以创建一个函数,该函数将基于毫秒数返回此类承诺。

你甚至可以创建一个输出内容并再次返回一个promise的函数。

这将允许您将整个链接在一起:

 doTasks().then(say.bind(null, 'all done')); function say(msg) { console.log(msg); return $.Deferred().resolve(msg).promise(); } function doTasks() { return task1().then(task2); } function delay(ms) { // one function for delaying as a promise var d = $.Deferred(); setTimeout(d.resolve.bind(null, ' delay completed'), ms); return say('starting delay of ' + ms + ' milliseconds...') .then(d.promise).then(say); } function task1() { return say('starting task1...').then(delay.bind(null, 10)) .then(task1A).then(task1B).then(say.bind(null, 'task1 done')); } function task1A() { return say('starting task1A...').then(delay.bind(null, 1000)) .then(say.bind(null, ' resolving task1A...')); } function task1B() { return say('starting task1B...').then(delay.bind(null, 1000)) .then(say.bind(null, ' resolving task1B...')); } function task2() { return say('starting task2...').then(delay.bind(null, 1000)) .then(say.bind(null, 'task2 done')); } 
 .as-console-wrapper { max-height: 100% !important; top: 0; }