promise写异步,比如5大步,每步都并发N个ajax请求,像裂变一样形成(N的5次方)个请求,怎么写?

也就是,第一大步有N个ajax请求,每个分别回调,每个回调又有N个ajax请求,现在是N*2个请求。

然后第三大步又是N*N个请求的回调各有N个请求,现在是N的三次方个请求。

这样一直到第五步,形成N的5次方个请求。

我希望的是:
1、不要等第一步的五个请求都完成,再去进入第二大步,我希望每个链条能有多快就有多快。每一大步的任意一个请求完成,它个人都立即进入后一步,而不是等大步内的N个请求都完成才进入下一步。

2、每一个请求get到的数据都要传递给该请求的下一步。

用promise的写法怎么写?

希望看到伪代码。

阅读 5.5k
7 个回答

问出这个问题,说明你对promise的使用还并不清楚。

说白了,你就是想要实现若干个互相之间不会相互干扰的操作链,不要用一个大步这样的描述,你首先就把自己给绕晕了。
每个操作后续都有N个操作,每个操作之间相互独立,每个操作完成立即执行它自己的后续。

单一的顺序操作链是这样的:

start()
    .then()
    .then()
    .then()

在promise的操作中,每一步都必须要要返回一个新的promise,为什么要这样做?想明白这个问题,你就知道怎么做了。


理论上每个promise都可以链接无数个后续动作,想要链接多个动作,这么写就行了:

start = new Promise(/*code*/);
move1 = start.then(/*code*/);
move2 = start.then(/*code*/);

move11 = move1.then(/*code*/);
move12 = move1.then(/*code*/);

move21 = move2.then(/*code*/);
move22 = move2.then(/*code*/);

start后面接了move1move2
move1后面接了move11move12
move2后面接了move21move22


写段简单的代码:

function delay(time, value) {
    return(new Promise(function executor(resolve) {
        setTimeout(function asyn() {
            console.log(value);
            resolve();
        }, time);
    }));
}
function log1(value) {
    return function handler() {
        return delay(3000, value)
    };
}
function log2(value) {
    return function handler() {
        return delay(1000, value)
    };
}
let start = log2("start:")(),
    move1 = start.then(log1('Step 1;')),
    move2 = start.then(log2('Step 2;')),
    move11 = move1.then(log1('Step 1.1;')),
    move12 = move1.then(log1('Step 1.2;')),
    move21 = move2.then(log2('Step 2.1;')),
    move22 = move2.then(log2('Step 2.2;'));

Promise.all() 并发执行

这应该是一个单子变换的问题。

我很好奇,什么样的应用场景需要并发这么多ajax请求?

仔细想了一下,似乎没必要用promise这么复杂的东西。

假设有任意四个自然数,比如1,3,4,7。

假设已经有一个服务器实现了ajax,服务器所做的事情就是把post来的数据加1,然后返回给客户端。

当客户端得到数据之后,把数据分别乘以1、2、3、4,然后分别发送到服务器。这么循环下去。

如果裂变5次,就是一共发送4 + 4x4 + 4x4x4 + 4x4x4x4 + 4x4x4x4x4次。

似乎并不用promise,用递归函数即可。

(假设已经引入jQuery):

var fourNumerial = [1,3,4,7];

function post(numerial, level, index) {
    if ( level <= 5 ) {
        $.post('server.php', {numerial:numerial}, function(data) {
            console.log('level:' + level + ' data:' + data + ' index:' + index);
            for (var i = 1; i < 5; i++) {
                post(data * i, level + 1, i);
            }
        });
    }
}

for (var i = 0; i < 4; i++) {
    post(fourNumerial[i], 1, i);
}

我感觉强行用promise属于添乱。
如果是用promise.all和race都不能实现我说的每个链条互相独立的原则。
如果是用五个then连缀,最初的promise对象应该传递的是一个数组,数组就是服务器返回的四个数据。既然是一次性返回,那么仍然不能实现我说的每个链条互相独立的原则。
如果是用递归+promise,那么promise其实也是没必要的,最终还是递归就够了。
算了就这样吧。谢谢大家。

补充:偶尔看到了一篇回答https://segmentfault.com/q/10... ,递归+promise,例子非常好,但是其实用promise只是为了证明promise确实可以这么用,但是实践中能不用还是不用吧。。

可以先将ajax转换成promise的方式,然后分步调用.

var ajax_1_1 = promise,
    ajax_2_1 = promise,
    ...
    ajax_n_1 = promsie;
 
var AJAX_1 = ajax_1_1.then( return ajax_1_2 ).then( return ajax_1_3 )....then( return ajax_1_n ),
    AJAX_2 = ajax_2_1.then( return ajax_2_2 ).then( return ajax_2_3 )....then( return ajax_2_n ),
    ...
    AJAX_n = ajax_n_1.then( return ajax_n_2 ).then( return ajax_n_3 )....then( return ajax_n_n );
    
Promise.all([AJAX_1,AJAX_2,...,AJAX_n])
        .then(all promise done);

Promsie.all等所有的promise链完成调用之后才触发.

按你的意思第一大步并不依赖上一大步的所有结果,如果是这样,
试试看下面的模拟代码,可以到Console中直接运行

//模拟ajax请求,sp 只是为了区别现在是第几步用的
var ajax_test = function(v,sp){
    return new Promise(function(ok,no){
        setTimeout(function(){
            console.log(v + " -> " + sp + ' --ok')
            var str = v+"."+sp
            ok([str+'_1',str+'_2']);
        },Math.random()*1000)
    })
}

var ajax1_Promise = function(a){
    return ajax_test(a,1).then(function(arr){
        var p1 = ajax2_Promise(arr[0]);
        var p2 = ajax2_Promise(arr[1]);
        //每一步要裂变几个都可以
        return Promise.all([p1,p2])
    })
}
var ajax2_Promise = function(a){
    return ajax_test(a,2).then(function(arr){
        var p1 = ajax3_Promise(arr[0]);
        var p2 = ajax3_Promise(arr[1]);
        return Promise.all([p1,p2])
    })
}
var ajax3_Promise = function(a){
    //假设第三步最后一步
    return ajax_test(a,3)
}

var arr = ["A","B"]
var arr_p = [];
arr.forEach(function(v){
    arr_p.push(ajax1_Promise(v))
})

Promise.all(arr_p).then(function(d){
    console.log(d);
    console.log("all ok")
})

结果类似这样

B -> 1 --ok
A -> 1 --ok
A.1_2 -> 2 --ok
A.1_2.2_1 -> 3 --ok
A.1_1 -> 2 --ok
A.1_1.2_2 -> 3 --ok
A.1_2.2_2 -> 3 --ok
B.1_2 -> 2 --ok
B.1_1 -> 2 --ok
B.1_2.2_1 -> 3 --ok
A.1_1.2_1 -> 3 --ok
B.1_2.2_2 -> 3 --ok
B.1_1.2_1 -> 3 --ok
B.1_1.2_2 -> 3 --ok
[Array[2], Array[2]]
all ok
推荐问题
宣传栏