一次Promise 实践:异步任务的分组调度

起因是在工作中遇到一个问题,可以用一个二维数组简单描述:

[[1,2,3],[4,5,6],[7,8,9]]

这里每个数字都代表“一个异步计算任务”, 每个子数组把1个或多个计算任务划分成组,要求是:每组内的计算任务并行执行,但是各个组间要顺序执行。具体说来就是先执行1,2,3 等获得全部的结果以后再执行4,5,6以此类推。最后返回的结果跟执行顺序相同。

经过了大概半小时的尝试与思考,我写出了一个版本:

function dispatch(groups) {
    var result = Promise.resolve([])
    groups.forEach(function (group) {
        result = result.then(function (prevVal) {

            var ps = []
            group.forEach(function (task) {
                ps.push(Promise.resolve(task))
            })

            return Promise.all(ps).then(function (r) {
                prevVal.push(r)
                return prevVal
            })
        })
    })
    return result
}

调用方法:

dispatch([[1,2,3],[4,5,6],[7,8,9]]).then(function (result) {
    console.log(result) //[[1,2,3],[4,5,6],[7,8,9]]
});

 

基本思路就是,从第一组开始,对其中的所有异步任务求值,求值成功后再开始第二组...最后当遍历完全部组后,返回结果。

可以简单描述为:resolve([1,2,3]).then([4,5,6]).then([7,8,9])

思路看似简单直观,但是如何动态的创建then 链条确实花费了我不少脑筋,写完代码后也对promise 有了更深刻的理解。

写完代码后我兴高采烈地拿给同事看,同事说我这个写得太复杂不容易看懂,他能写出一个更简单直观的递归方案,大概十分钟后他拿出代码:

function dispatch(groups) {
    var results = []
    return (function () {
        var fun = arguments.callee
            , group = groups.shift()
        if (!group) {
            return Promise.resolve(results)
        }

        var promises = []
        group.forEach(function (task) {
            promises.push(
                Promise.resolve(task)
            )
        })

        return Promise.all(promises).then(function (rets) {
            results.push(rets)
            return fun()
        })
    }())
} 

貌似真的比我那个要直观,但是貌似这个方案要比我那个多创建一个Promise 对象,而且代码行数也略多一点。无论怎样我最重还是选了同事的方案。。毕竟可读性第一嘛。

posted @ 2015-05-02 14:55  Agentgamer  阅读(924)  评论(0编辑  收藏  举报