我编写了一个小程序来帮助我理解如何在jquery中执行嵌套异步promise。
我想按顺序调用两个任务。第一个任务有两个也按顺序调用的子任务。这就是全部。
虽然这有效,但我怀疑这是否是使用承诺的最佳方式。必须为每个任务创建一个新的延迟感觉就像代码闻到我。例如,传递一个延迟对象并仅使用它会更好吗?谢谢!
https://plnkr.co/edit/dyFFqqZhCVuhBYCuWjzm?p=preview
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()
}
答案 0 :(得分:2)
是的,创造许多不必要的延期是有点臭。
您无需为ajax操作创建任何延迟。如果从.then()
处理程序中返回一个promise,它将自动链接到前一个promise(从而对它进行排序),并且所有jquery ajax调用都已返回promise。因此,您无需为ajax操作创建任何自己的承诺。并且,您可以链接而不是嵌套,以便对操作进行排序。
事实上,在您不需要时创建延期或承诺称为promise anti-pattern。您希望使用并返回已创建的承诺,而不是创建新承诺。并且,在可能的情况下,您希望将承诺链接起来而不是嵌套。
以下是如何在可运行的代码段中执行此操作而不创建一个延迟,除了在承诺中包装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";
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
答案 1 :(得分:2)
你不应该承诺你的承诺。这个想法是你通过在第一个then
回调中返回一个值来链接它们,并链接下一个then
,它在自己的回调中将执行下一步,等等。
当您在多个地方使用计时器来解决承诺时,您可以创建一个函数,该函数将基于毫秒数返回此类承诺。
您甚至可以创建一个输出内容并再次返回承诺的函数。
这将允许你将整个链条连在一起:
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'));
}
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
&#13;