如何与Bluebird Promises进行分页?

时间:2015-02-16 19:43:55

标签: 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

limit设置为某个任意数字,例如10skip0开始。我希望不断增加skip,直到不再有trades

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

这是第一次使用,但我希望以分页方式获得更多交易。具体来说,我希望trader.getTrades运行skip更高trades.length,直到{{1}}为0

3 个答案:

答案 0 :(得分:8)

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

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)
}

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

答案 1 :(得分:8)

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

var getTrades = Promise.promisify(trader.getTrades, trader);

现在,为了遍历那个分页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));
    });
}

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

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

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

答案 2 :(得分:1)

这是我自己的解决方案,分析承诺:方法page,作为spex库的一部分。

它还允许您根据需要限制处理并提供负载平衡。

实施例

var promise = require('bluebird');
var spex = require('spex')(promise);

function source(index, data, delay) {
    // create and return an array/page of mixed values
    // dynamically, based on the index of the sequence;
    switch (index) {
        case 0:
            return [0, 1, promise.resolve(2)];
        case 1:
            return [3, 4, promise.resolve(5)];
        case 2:
            return [6, 7, promise.resolve(8)];
    }
    // returning nothing/undefined indicates the end of the sequence;
    // throwing an error will result in a reject;
}

function dest(idx, data, delay) {
    // data - resolved array data;
    console.log("LOG:", idx, data, delay);
}

spex.page(source, dest)
    .then(function (data) {
        console.log("DATA:", data); // print result;
    });

输出

LOG: 0 [ 0, 1, 2 ] undefined
LOG: 1 [ 3, 4, 5 ] 3
LOG: 2 [ 6, 7, 8 ] 0
DATA: { pages: 3, total: 9, duration: 7 }