码迷,mamicode.com
首页 > 其他好文 > 详细

一次Promise 实践(2):DataPath 的复用

时间:2015-07-18 02:01:17      阅读:107      评论:0      收藏:0      [点我收藏+]

标签:

跟上一篇“一次Promise 实践:异步任务的分组调度” 一样,这次的同样是来自于工作中实际碰到的问题。

这次遇到的问题可以比喻成要对一批原料进行加工,其中开头的一些工序是一样的,好比流水线,开头一段是一样的,后面却分为两道流水,在此基础上分别生产不同的产品。

              o--o--o 产品1
             /    
原料o--o--o--o
                           o--o--o 产品2

这里的原料就是要处理的原始数据,可以用数组表示:

var raw = [1, 2, 3, 4, 5]

各个原始数据经过公共部分处理以后应该得到:

[comm(1), comm(2), comm(3), comm(4), comm(5)]

经过两条流水线分别处理后应该得到:

p1 = [p1(comm(1)), p1(comm(2)), p1(comm(3)), p1(comm(4)), p1(comm(5))]
p2 = [p2(comm(1)), p2(comm(2)), p2(comm(3)), p2(comm(4)), p2(comm(5))]

 

方案1: 有了上一次的经验,我想通过动态的创建一系列then 链条来完成工作,分别用两个promise 对象来保存两条流水线的最终结果:

var main = Promise.resolve()
var branch1 = Promise.resolve([])
var branch2 = Promise.resolve([])
var list = [1, 2, 3, 4, 5]

list.forEach(function (id) {
    main = main.then(function () {return "comm(" + id + ")"
    })
    .then(function (comm) {
        branch1 = branch1.then(path1(comm))
        branch2 = branch2.then(path2(comm))
    })
})

setTimeout(function () {
    branch1.then(function (final) {
        console.log("branch1: ")
        console.log(final)
    })

    branch2.then(function (final) {
        console.log("branch2: ")
        console.log(final)
    })
}, 0)

function path2(id) {
    return function (prev) {
        var ret = "bran2(" + id + ")"
        prev.push(ret)
        return prev
    }
}

function path1(id) {
    return function (prev) {
        var ret = "bran1(" + id + ")"
        prev.push(ret)
        return prev
    }
}

打印结果:

branch1: 
[ ‘bran1(comm(1))‘,
  ‘bran1(comm(2))‘,
  ‘bran1(comm(3))‘,
  ‘bran1(comm(4))‘,
  ‘bran1(comm(5))‘ ]
branch2: 
[ ‘bran2(comm(1))‘,
  ‘bran2(comm(2))‘,
  ‘bran2(comm(3))‘,
  ‘bran2(comm(4))‘,
  ‘bran2(comm(5))‘ ]

  这里需要注意的是在收集branch1 和 branch2 的结果时需要使用setTimeout。依我对runtime的有限理解,是因为要确保回调函数不在本次tick 中被加入事件队列,因为forEach中的那些处理过程需要先于收集过程执行。

这样就清晰的把两个流水线上的数据分别保存在两个promise 对象中,看起来非常讨喜。

 

方案二,不使用promise 对象来保存结果

var total = []
var p1r = []
var p2r = []
list.forEach(function (id) {
    main = main.then(function() {
        return "comm(" + id + ")"
    })
    .then(function (comm) {
        var promises = [path1(comm), path2(comm)]
        return Promise.all(promises)
    })
    .then(function (re) {
        total.push(re)
    })
})

g.then(function() {
    total.forEach(function (e) {
        p1r.push(e[0])
        p2r.push(e[1])
    })

    console.log("p1")
    console.log(p1r)
    console.log("p2")
    console.log(p2r)
})

function path1(d) {
    return Promise.resolve("p1(" + d + ")")
}

function path2(d) {
    return Promise.resolve("p2(" + d + ")")
}

这个方法其实跟方案一大同小异,只是没有再使用两个promise 对象,而是使用了普通数组。然后不同分支的操作使用promise.all 来执行,最后的结果做一点点处理。好处是不再有setTimeout了。

 

方案三,利用递归

function c (list) {
    var retA = []
    var retB = []
    return (function() {
        if (!list || list.length == 0) return [retA, retB]
        var func = arguments.callee
            , head = list.shift()
        return Promise.resolve("common("+ head + ")")
                .then(function (comm) {
                    return Promise.all([resolveA(comm), resolveB(comm)])
                })
                .then(function (ret) {
                    retA.push(ret[0])
                    retB.push(ret[1])
                    return func(list)
                })
    })()
}

function resolveA(d) {
    return Promise.resolve("p1("+ d + ")")
} 

function resolveB(d) {
    return Promise.resolve("p2("+ d + ")")
}

调用:

c([1, 2, 3, 4, 5]).then(function (e) {
    console.log(e)
})

结果:

[ [ ‘p1(common(1))‘,
    ‘p1(common(2))‘,
    ‘p1(common(3))‘,
    ‘p1(common(4))‘,
    ‘p1(common(5))‘ ],
  [ ‘p2(common(1))‘,
    ‘p2(common(2))‘,
    ‘p2(common(3))‘,
    ‘p2(common(4))‘,
    ‘p2(common(5))‘ ] ]

第三个方案其实是方案二的递归版本,但是比方案二更简洁,递归的引入使代码变得很短。

 

思考:如何添加更多的分支?是否可以将整个过程模块化,框架化?哪个方案更容易拓展?(我个人倾向于使用方案一,因为最终得到两个promise 对象后我可以继续then下去……)

一次Promise 实践(2):DataPath 的复用

标签:

原文地址:http://www.cnblogs.com/agentgamer/p/4655955.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!