我是Node和异步编程模型的新手。我在处理在同步环境中看起来很基本的简单要求时遇到了问题:通过API响应进行分页直到响应为空。
更具体地说,API在成功调用后将返回数据,并且状态为200或206(部分内容)。如果看到206响应,则需要继续调用API(还会发送每次递增的page
查询参数),直到看到200响应为止。
在同步语言中,任务将是小菜一碟:
// pseudocode
data = []
page = 1
do {
response = api.call(page)
data.append(response.data)
page++
} while (response != 200)
return data
现在,在Node中,对于单个api调用,这样的代码将起作用:
// fire when '/' has a GET request
app.get('/', (req, res) => {
axios.get('https://api.com/v1/cats')
.then(response => {
// now what??
});
});
});
看到//now what??
评论吗?这就是我想知道如何进行的地方。我碰到了this有点相关的帖子,但是无法将其转换为适用于Node和Axios的格式。
仅将axios代码包装在单独的函数中是否足够?我不这么认为,因为如果我这样做:
function getData(pageNum) {
axios.get('https://api.com/v1/cats')
.then(response => {
// now what??
});
});
}
我不能依赖返回值,因为一旦执行axios.get()
,函数便结束了。得到第一个响应后,我可以再次调用getData()
,但是,假设我想将这些多个调用中的所有数据作为我的Express服务器的HTTP响应返回。 。 。我该怎么办?
我希望我不会因懒惰或其他原因而感到失望。我确实环顾四周,但没有发现任何相关内容。
答案 0 :(得分:1)
首先,一个反问:数据集太大了,您需要担心用完所有内存吗?因为如果是这样,那么将需要更多的工作来以完全流式传输数据的方式来构造代码。 (实际上,我什至不确定express是否允许流式传输...您使用的不是吗?)
从axios文档中,看来response
是可读的流,提供了响应正文。因此,阅读它也是一个异步任务。因此,您应该编写一个执行此操作的函数。有关更多详细信息,请参见nodejs文档的“ Stream”页面。或者,如果时间允许,也可以说服我为您提供帮助。但是现在,我假设您有一个函数readResponse
,该函数将axios响应对象作为参数并返回一个Promise,并且Promise解析为诸如{ statusCode: 206, result: ['thing1', 'thing2'] }
之类的对象。我还将假设您的目标是获取所有result
数组并将它们连接在一起以获得例如['thing1', 'thing2', 'thing3', 'thing4', 'thing5', 'thing6']
。
您可以编写getData
函数的自调用版本。将从指定页面开始(而不是页面本身)检索所有数据:
function getData(pageNum) {
axios.get('https://api.com/v1/cats' + (pageNum ? '?page=' + pageNum) : '')
.then(readResponse)
.then(function(parsedResponse) {
if(parsedResponse.statusCode == 200) {
return parsedResponse.result;
} else if(parsedResponse.statusCode == 206) {
return getData(pageNum + 1).then(function(laterData) {
return parsedResponse.result.concat(laterData);
});
} else {
// error handling here, throw an exception or return a failing promise.
}
});
});
}
然后,要获取所有数据,只需使用pageNum = 0
调用此函数:
// fire when '/' has a GET request
app.get('/', (req, res) => {
getData(0)
.then(function(results) {
// results is now the array you want.
var response = JSON.stringify(results); // or whatever you're doing to serialise your data
res.send(response);
});
});