jQuery:按顺序执行函数数组(递延和非递延) [英] jQuery: execute array of functions sequentially (both deferreds and non-deferreds)

查看:77
本文介绍了jQuery:按顺序执行函数数组(递延和非递延)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对使用Promises还是很陌生,很难把头放在jQuery延迟上.

I am fairly new to using Promises and have a hard time of wrapping my head around jQuery deferreds.

我目前拥有的是在特定点执行的一系列函数:

What I currently have is an array of functions which I execute at a certain point:

while (queue.length) {
    (queue.shift())();   
}

问题是,其中一些功能是异步的,但我需要它们一个接一个地运行.

The problem with this is, that some of those functions are asynchronous, but I need them to run one after another.

因此,队列中的某些函数会返回延迟(例如,通过jQuery.ajax()),而某些只是普通函数.我想知道是否有可能按顺序+按顺序执行它们(仅在上一个函数完成后才执行下一个函数).

So some of the functions in the queue return a deferred (e.g. via jQuery.ajax()) and some are just normal functions. I would like to know if how it would be possible to execute them in order + sequentially (executing the next function only when the previous one has finished).

我以为可能是jQuery.when正是我想要的东西,但是我不知道该怎么做,我只想到了这个:

I thought maybe jQuery.when would be what I am looking for, but I can't figure out how to it exactly, I came only up with this:

var deferred = jQuery.Deferred();
    while (queue.length > 0) {
       deferred.done().then(queue.shift());
    }

推荐答案

非常精明,jQuery.when .它接受一个承诺或一个正常的不可兑现的承诺,并返回一个超过该值的承诺.但是,由于这里有函数而不是值,实际上并不是必需的,因为这始终是.then的行为.

Very astute, jQuery.when is what you're looking for. It takes either a promise or a normal non-thenable and returns a promise over that value. However, since you have functions and not values here that isn't really required since this is the behavior of .then anyway.

var queue = [syncFunction, syncFunc2, returnsPromiseAsync];

var d = $.Deferred().resolve();
while (queue.length > 0) {
   d = d.then(queue.shift()); // you don't need the `.done`
}

(小提琴)

或者,您可以减少;

var res = queue.reduce(function(prev,cur){ // chain to res later to hook on done
    return prev.then(cur);
}, $.Deferred().resolve());

如果您有更多代码可以执行以下操作,则由于队列中的函数可以同步或异步运行(或同步运行,然后我们遇到了异步运行),为避免混乱,您可能需要确保函数始终运行异步地.通过将resolve包裹在setTimeout中的初始Deferred上,您可以轻松地做到这一点:

If you have more code doing things below this, since the functions in the queue may run synchronously or asynchronously (or some synchronous and then we hit an async one), to avoid chaos you may want to ensure that the functions always run asynchronously. You can easily do that by wrapping the resolve on the initial Deferred in a setTimeout:

var p = $.Deferred();
var res = queue.reduce(function(prev,cur){ // chain to res later to hook on done
    return prev.then(cur);
}, p);
setTimeout(p.resolve.bind(p), 0);

现在,直到超时发生,该过程才会开始,并且此后的任何代码都肯定会在队列中的第一个函数之前运行.在我看来,这与jQuery的诺言的语义不一致(因为它们在同步与异步方面不一致.回调),但您可能需要保持一致性.

Now the process won't start until the timeout occurs, and any code following this will definitely run before the first function from the queue does. In my view, that's inconsistent with the semantics of jQuery's promises (because they are inconsistent about sync vs. async callbacks), but you may want the consistency.

如果您需要知道进程何时完成,只需在res上使用.then处理程序:

If you need to know when the process completes, just use a .then handler on res:

res.then(function() {
    // All functions have now completed
});

在这种情况下,这是一个简单的包装函数,可同时执行以下操作:

For those situations, here's a simple wrapper function that does both:

function clearQueue(q) {
    var p = $.Deferred();
    setTimeout(p.resolve.bind(p), 0);

    return q.reduce(function(prev,cur){ 
        return prev.then(cur);
    }, p);
}

示例用法(小提琴):

clearQueue(queue).then(function() {
    console.log("All done");
});
console.log("This runs before any queued function starts");

这篇关于jQuery:按顺序执行函数数组(递延和非递延)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆