jQuery的异步循环deferred (promises)
Asynchronous Loop of jQuery Deferreds (promises)
我正在尝试创造我认为被称为"瀑布"的东西。我想按顺序处理异步函数数组(jQuery承诺)。
下面是一个做作的例子:
function doTask(taskNum){
var dfd = $.Deferred(),
time = Math.floor(Math.random()*3000);
setTimeout(function(){
console.log(taskNum);
dfd.resolve();
},time)
return dfd.promise();
}
var tasks = [1,2,3];
for (var i = 0; i < tasks.length; i++){
doTask(tasks[i]);
}
console.log("all done");
我希望它按照它们执行的顺序(存在于数组中)完成任务。所以,在这个例子中,我想让它做任务1,等待它解析,然后做任务2,等待它解析,做任务3,等等,日志"所有完成"。
也许这真的很明显,但我已经想了一下午了
我会尝试在这里使用$().queue
而不是$.Deferred
。将函数添加到队列中,只有当准备好时才调用下一个函数。
function doTask(taskNum, next){
var time = Math.floor(Math.random()*3000);
setTimeout(function(){
console.log(taskNum);
next();
},time)
}
function createTask(taskNum){
return function(next){
doTask(taskNum, next);
}
}
var tasks = [1,2,3];
for (var i = 0; i < tasks.length; i++){
$(document).queue('tasks', createTask(tasks[i]));
}
$(document).queue('tasks', function(){
console.log("all done");
});
$(document).dequeue('tasks');
对于瀑布,你需要一个异步循环:
(function step(i, callback) {
if (i < tasks.length)
doTask(tasks[i]).then(function(res) {
// since sequential, you'd usually use "res" here somehow
step(i+1, callback);
});
else
callback();
})(0, function(){
console.log("all done");
});
可以创建一个解析过的$。延迟,每次迭代只添加到链中:
var dfd = $.Deferred().resolve();
tasks.forEach(function(task){
dfd = dfd.then(function(){
return doTask(task);
});
});
一步步地发生着:
//begin the chain by resolving a new $.Deferred
var dfd = $.Deferred().resolve();
// use a forEach to create a closure freezing task
tasks.forEach(function(task){
// add to the $.Deferred chain with $.then() and re-assign
dfd = dfd.then(function(){
// perform async operation and return its promise
return doTask(task);
});
});
我个人认为这比递归更简洁,比$()更熟悉。$()的jQuery API。队列是令人困惑的,因为它是为动画设计的,它也可能是你使用$。Deferred在代码的其他地方)。它还具有通过异步操作中的resolve()将结果按瀑布式标准传输的优点,并允许附加$。做财产。
在jsFiddle中
看一下$。When和then方法的运行延迟。
瀑布用于将返回值从一个递延到下一个的管道串联起来。它看起来像这样。
function doTask (taskNum) {
var dfd = $.Deferred(),
time = Math.floor(Math.random() * 3000);
console.log("running task " + taskNum);
setTimeout(function(){
console.log(taskNum + " completed");
dfd.resolve(taskNum + 1);
}, time)
return dfd.promise();
}
var tasks = [1, 2, 3];
tasks
.slice(1)
.reduce(function(chain) { return chain.then(doTask); }, doTask(tasks[0]))
.then(function() { console.log("all done"); });
注意传递给resolve
的参数。它被传递给链中的下一个函数。如果您只是想在不输入参数的情况下串行运行它们,则可以将其取出并将reduce调用更改为.reduce(function(chain, taskNum) { return chain.then(doTask.bind(null, taskNum)); }, doTask(tasks[0]));
同时它看起来像这样:
var tasks = [1,2,3].map(function(task) { return doTask(task); });
$.when.apply(null, tasks).then(function() {
console.log(arguments); // Will equal the values passed to resolve, in order of execution.
});
确实是个有趣的挑战。我想到的是一个递归函数,它接受一个列表和一个可选的起始索引。
这里是一个链接到jsFiddle,我已经测试了几个不同的列表长度和间隔。
我假设你有一个返回承诺的函数列表(不是数字列表)。如果你有一个数字列表,你可以修改这部分
$.when(tasks[index]()).then(function(){
deferredSequentialDo(tasks, index + 1);
});
/* Proxy is a method that accepts the value from the list
and returns a function that utilizes said value
and returns a promise */
var deferredFunction = myFunctionProxy(tasks[index]);
$.when(tasks[index]()).then(function(){
deferredSequentialDo(tasks, index + 1);
});
我不确定你的函数列表有多大,但要知道浏览器将从第一个deferredSequentialDo调用中保留资源,直到它们全部完成。
参数
- items:参数数组
- func:异步函数
- callback:回调函数
- update:更新功能
简单的循环:
var syncLoop = function(items, func, callback) {
items.reduce(function(promise, item) {
return promise.then(func.bind(this, item));
}, $.Deferred().resolve()).then(callback);
};
syncLoop(items, func, callback);
跟踪进度:
var syncProgress = function(items, func, callback, update) {
var progress = 0;
items.reduce(function(promise, item) {
return promise.done(function() {
update(++progress / items.length);
return func(item);
});
}, $.Deferred().resolve()).then(callback);
};
syncProgress(items, func, callback, update);
- 可以简化嵌套的延迟Q Promises解析吗
- JQuery Deferred Ajax,将结果保存在调用对象中
- 如何制作Deferred对象的数组
- Working with Ajax Promises / Deferred
- ExpressJS/NodeJS/Promises:从promise链提前返回
- 用Promises返回的数据替换出现的文本
- Jasmine中返回Deferred的模拟嵌套函数
- jQuery Deferred and promise-错误:对象没有't支持属性或方法'然后'
- 强制jQuery Deferred等待Ajax在“”中完成;那么“;处理程序
- 如何用JQuery$.Deferred重写AJAX调用
- JS Promises如何在内部工作
- 尝试使用Promises删除记录
- 为什么我们在javascript中使用Deferred()
- Backbone JS Promises在模型上设置属性之前解析
- 我可以将Promises传递给jQuery.when(),还是只传递Deferred
- jQuery Deferred/Promises with many getJSON
- 在jQuery中使用.then()链接promises/Deferred
- 类似于promises/deferred's的模式,支持多个结果和取消
- jQuery的异步循环deferred (promises)
- Promises和Deferred:调用了.done()和.then(),但对Deferred对象调用了.resolve