如何使用 Bluebird Promises 进行分页?
How can I do pagination with Bluebird Promises?
我有类似的东西
new Promise (resolve, reject) ->
trader.getTrades limit, skip, (err, trades) ->
return reject err if err
resolve trades
.each (trade) ->
doStuff trade
limit
设置为某个任意数字,例如 10
和 skip
从 0
开始。我想继续增加 skip
直到没有更多 trades
.
doStuff
是我用来处理每笔交易的函数。
这是第一次成功,但我想以分页方式获得更多交易。具体来说,我想 运行 trader.getTrades
具有更高的 skip
直到 trades.length
为 0
您应该能够使用 promisify()
/promisifyAll()
将 trader.getTrades()
转换为 returns 承诺的异步版本。然后,像这样的东西应该可以正常工作:
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 页交易。
首先,让我们隐藏那个丑陋的回调 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
不是超级快,因为它会在每次请求后创建一个新数组,但这是最优雅的。
此函数将 return 一个承诺,当所有请求都发出时,该承诺会解析出大量的所有结果。这当然可能不是你想要的——也许你想立即显示第一个结果,然后延迟加载更多?那么单个承诺不是您想要的工具,因为这种行为更像流。然而,它仍然可以用 promises 来写:
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
这是我自己的通过 promise 进行分页的解决方案:方法 page, as part of the 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 }
我有类似的东西
new Promise (resolve, reject) ->
trader.getTrades limit, skip, (err, trades) ->
return reject err if err
resolve trades
.each (trade) ->
doStuff trade
limit
设置为某个任意数字,例如 10
和 skip
从 0
开始。我想继续增加 skip
直到没有更多 trades
.
doStuff
是我用来处理每笔交易的函数。
这是第一次成功,但我想以分页方式获得更多交易。具体来说,我想 运行 trader.getTrades
具有更高的 skip
直到 trades.length
为 0
您应该能够使用 promisify()
/promisifyAll()
将 trader.getTrades()
转换为 returns 承诺的异步版本。然后,像这样的东西应该可以正常工作:
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 页交易。
首先,让我们隐藏那个丑陋的回调 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
不是超级快,因为它会在每次请求后创建一个新数组,但这是最优雅的。
此函数将 return 一个承诺,当所有请求都发出时,该承诺会解析出大量的所有结果。这当然可能不是你想要的——也许你想立即显示第一个结果,然后延迟加载更多?那么单个承诺不是您想要的工具,因为这种行为更像流。然而,它仍然可以用 promises 来写:
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
这是我自己的通过 promise 进行分页的解决方案:方法 page, as part of the 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 }