jQuery的Deferreds的异步环路(许诺)(Asynchronous Loop of jQu

2019-07-22 00:53发布

我想创造什么,我认为是被称为“瀑布”。 我想顺序地处理的异步函数(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和日志“全部完成”。

也许这真的是明显的,但我一直在尝试所有下午摸不着头脑。

Answer 1:

我会尝试使用$().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');


Answer 2:

对于一个瀑布,你需要一个异步循环:

(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");
});


Answer 3:

您可以创建一个解决$ .Deferred,只是添加到与每个迭代的链条:

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在其他地方你码)。 它也有结果的标准传递而下的瀑布,通过解析()的异步操作,并允许$ .done属性的附加的好处。

这是一个的jsfiddle



Answer 4:

看一看在$。当和再运行deferreds方法。

瀑布是用来管返回值从一推迟到下一个串联。 它看起来会是这样 。

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(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.
});


Answer 5:

的确是有趣的挑战。 我想出了是接受列表和可选的开始索引递归函数。

这里是对的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呼叫保持到资源,直到他们都完成了。



Answer 6:

参数

  • 项目:参数数组
  • FUNC:异步功能
  • 回调:回调函数
  • 更新:更新功能

简单的循环:

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);


文章来源: Asynchronous Loop of jQuery Deferreds (promises)