如何与Bluebird Promises进行分页?

Sha*_*oon 7 javascript node.js promise bluebird

我有类似的东西

new Promise (resolve, reject) ->
  trader.getTrades limit, skip, (err, trades) ->
    return reject err if err

    resolve trades
.each (trade) ->
  doStuff trade
Run Code Online (Sandbox Code Playgroud)

limit被设置为某个任意数字,比如说10,skip从头开始0.我想继续增加,skip直到没有更多trades.

doStuff是我用来处理每笔交易的函数.

这是第一次,但我希望以分页方式获得更多交易.具体来说,我想trader.getTrades用更高的运行skip直到trades.length0

aar*_*sil 8

您应该能够使用promisify()/promisifyAll()转换trader.getTrades()为返回promise的异步版本.然后,这样的事情应该很好:

function getAllTrades(limit, offset, query) {

    var allTrades = [];

    function getTrades(limit, offset, query){
        return trader.getTradesAsync(limit, offset, query)
            .each(function(trade) {
                allTrades.push(trade)
                // or, doStuff(trade), etc.
            })
            .then(function(trades) {
                if (trades.length === limit) {
                    offset += limit;
                    return getTrades(limit, offset, query);
                } else {
                    return allTrades;
                }
            })
            .catch(function(e) {
                console.log(e.stack);
            })
    }

    return getTrades(limit, offset, query)
}
Run Code Online (Sandbox Code Playgroud)

如果您事先知道交易总数,则可以使用不同的策略,.map{concurrency: N}立即获得N页交易.


Ber*_*rgi 8

首先,让我们隐瞒丑陋的回调api:

var getTrades = Promise.promisify(trader.getTrades, trader);
Run Code Online (Sandbox Code Playgroud)

现在,为了遍历那个分页api,我们将使用一个简单的递归下降:

function getAllTrades(limit, arr) {
    if (!arr) arr=[];
    return getTrades(limit, arr.length).then(function(results) {
         if (!results.length)
             return arr;
         else
             return getAllTrades(limit, arr.concat(results));
    });
}
Run Code Online (Sandbox Code Playgroud)

不可否认,concat并不是超快,因为它在每个请求后创建一个新数组,但这是最优雅的.

此函数将返回一个promise,该promise将在发出所有请求时以大量所有结果解析.这当然可能不是你想要的 - 也许你想立即显示第一个结果,并且只是懒得加载?然后单个承诺不是您想要的工具,因为此行为更像流.然而,它可以写成承诺:

getTradeChunks = (limit, start = 0) ->
  getTrades limit, start
  .then (chunk) ->
    throw new Error("end of stream") if not chunk.length
    s = start+chunk.length
    [chunk, -> getTradeChunks limit, s]

rec = ([chunk, cont]) ->
  Promise.each chunk, doStuff
  .then -> waitForClick $ "#more"
  .then cont
  .then rec, err
end = (err) ->
  $ "#more"
  .text "no more trades"
getTradeChunks 15
.then rec, err
Run Code Online (Sandbox Code Playgroud)