让 Node 等到所有数据都加载完毕才发送响应
Let Node wait till all data is loaded to send response
情况示意图
我正在用 Node.js 和 express and a mongodb 制作一个网络服务器。我将在我的 Android 应用程序的主页片段中将一些系列表示为一个列表。类似于下图:
红色矩形是一个包含多个系列的列表。
数据
在数据库中,我创建了一个名为 lists
的集合。这是一个文档示例:
{
"_id" : ObjectId("486464a459f14e486012ee4a"),
"name" : "Flemish",
"series" : [ 61519, 64095, 11431, 16148, 63315, 68667, 8318, 61548, 62025, 36960 ]
}
属性 series
在每个文档中的长度不同。
该数组中的数字代表系列中的 ID。他们来自 The Movie Database (TMDb).
我会怎样
现在我将数据库中的列表与 TMDb 中的数据合并。为此,我编写了以下代码:
const dbService = require("./../data/databaseService.js"),
apiService = require("./../data/apiService.js"),
express = require("express"),
router = express.Router();
router.get("/list", (req, res, next) => {
dbService.getLists((err, data) => {
if (err) {
next(err);
}
else {
let seriesData = [];
for (var listIndex = data.length - 1; listIndex--;) {
let temp = {
name: data[listIndex].name,
series: []
};
for (var seriesIndex = data[listIndex].series.length - 1; seriesIndex--;) {
let id = data[listIndex].series[seriesIndex];
apiService.request(`tv/${id}?append_to_response=images,similar`, (err, data) => {
if (err) {
next(err);
}
else {
temp.series.push(data);
}
});
}
seriesData.push(temp);
}
res.send(seriesData);
}
});
});
module.exports = router;
问题
我遇到的问题是行 res.send(seriesData);
在 数据被推送到数组 seriesData
之前被调用 。这发生在这条线上 temp.series.push(data);
。您可以在下面找到将要发送的代码:
[
{
"name": "British",
"series": []
},
{
"name": "American",
"series": []
},
{
"name": "Reality",
"series": []
},
{
"name": "Flemish",
"series": []
}
]
我知道一切都与 Node.js 异步发生,我对结果并不感到震惊,但现在 Node 必须等待。
问题
现在我的问题是,响应是否可以等到所有数据从TMDb 加载完成?如果是如何,否则为什么?
另请注意,列表中的项目必须相等。示例:系列"Game of thrones" 位于美国列表中,不能被推到另一个列表中。与系列 "Als de dijken breken" 相同。该系列进入弗拉芒语列表,无法推入英国语。
参考
我制作了一张图片,您可以在其中再次检查代码并获得每个请求和响应的结果作为 JSON 代码。
(点击图片查看实际尺寸)
经过搜索和测试,我终于找到了解决方案。
图书馆
对于库,我使用 Async.js。您可以在命令行中使用以下代码来安装它:
npm install --save async
并使用这个添加库
const async = require("async");
我使用 async.each()
方法。
This is the simpler solution to the problem. The function takes an array of items, then iterates over them calling a wrapper function which accepts the item as an argument. When all the calls are complete, you specify a final function to be called.
// 1st para in async.each() is the array of items
async.each(items,
// 2nd param is the function that each item is passed to
function(item, callback){
// Call an asynchronous function, often a save() to DB
item.someAsyncCall(function (){
// Async call is done, alert via callback
callback();
});
},
// 3rd param is the function to call when everything's done
function(err){
// All tasks are done now
doSomethingOnceAllAreDone();
}
);
提示:使用命名函数。
代码
您可以在下面找到我使用的代码:
const dbService = require("./../data/databaseService.js"),
apiService = require("./../data/apiService.js"),
express = require("express"),
async = require("async"),
router = express.Router();
router.get("/list", (req, res, next) => {
dbService.getLists((err, data) => {
if (err) {
next(err);
}
else {
let seriesData = [],
apiRequests = [];
for (let listIndex = data.length; listIndex--;) {
let theName = data[listIndex].name;
seriesData.push({
name: theName,
series: []
});
for (let seriesIndex = data[listIndex].series.length; seriesIndex--;) {
let id = data[listIndex].series[seriesIndex];
apiRequests.push({
destinationListName: theName,
tmdbId: id
});
}
}
let apiCall = (apiReq, cb) => {
apiService.request(`tv/${apiReq.tmdbId}?append_to_response=images,similar`, (err, data) => {
if (err) {
next(err);
}
else {
for (let listIndex = seriesData.length; listIndex--;) {
let name = seriesData[listIndex].name;
if (name == apiReq.destinationListName) {
seriesData[listIndex].series.push(data);
cb();
}
}
}
});
},
afterApiCall = (err) => {
if (err) {
next(err);
}
else {
res.send(seriesData);
}
};
async.each(apiRequests, apiCall, afterApiCall);
}
});
});
module.exports = router;
情况示意图
我正在用 Node.js 和 express and a mongodb 制作一个网络服务器。我将在我的 Android 应用程序的主页片段中将一些系列表示为一个列表。类似于下图:
红色矩形是一个包含多个系列的列表。
数据
在数据库中,我创建了一个名为 lists
的集合。这是一个文档示例:
{
"_id" : ObjectId("486464a459f14e486012ee4a"),
"name" : "Flemish",
"series" : [ 61519, 64095, 11431, 16148, 63315, 68667, 8318, 61548, 62025, 36960 ]
}
属性 series
在每个文档中的长度不同。
该数组中的数字代表系列中的 ID。他们来自 The Movie Database (TMDb).
我会怎样
现在我将数据库中的列表与 TMDb 中的数据合并。为此,我编写了以下代码:
const dbService = require("./../data/databaseService.js"),
apiService = require("./../data/apiService.js"),
express = require("express"),
router = express.Router();
router.get("/list", (req, res, next) => {
dbService.getLists((err, data) => {
if (err) {
next(err);
}
else {
let seriesData = [];
for (var listIndex = data.length - 1; listIndex--;) {
let temp = {
name: data[listIndex].name,
series: []
};
for (var seriesIndex = data[listIndex].series.length - 1; seriesIndex--;) {
let id = data[listIndex].series[seriesIndex];
apiService.request(`tv/${id}?append_to_response=images,similar`, (err, data) => {
if (err) {
next(err);
}
else {
temp.series.push(data);
}
});
}
seriesData.push(temp);
}
res.send(seriesData);
}
});
});
module.exports = router;
问题
我遇到的问题是行 res.send(seriesData);
在 数据被推送到数组 seriesData
之前被调用 。这发生在这条线上 temp.series.push(data);
。您可以在下面找到将要发送的代码:
[
{
"name": "British",
"series": []
},
{
"name": "American",
"series": []
},
{
"name": "Reality",
"series": []
},
{
"name": "Flemish",
"series": []
}
]
我知道一切都与 Node.js 异步发生,我对结果并不感到震惊,但现在 Node 必须等待。
问题
现在我的问题是,响应是否可以等到所有数据从TMDb 加载完成?如果是如何,否则为什么?
另请注意,列表中的项目必须相等。示例:系列"Game of thrones" 位于美国列表中,不能被推到另一个列表中。与系列 "Als de dijken breken" 相同。该系列进入弗拉芒语列表,无法推入英国语。
参考
我制作了一张图片,您可以在其中再次检查代码并获得每个请求和响应的结果作为 JSON 代码。
经过搜索和测试,我终于找到了解决方案。
图书馆
对于库,我使用 Async.js。您可以在命令行中使用以下代码来安装它:
npm install --save async
并使用这个添加库
const async = require("async");
我使用 async.each()
方法。
This is the simpler solution to the problem. The function takes an array of items, then iterates over them calling a wrapper function which accepts the item as an argument. When all the calls are complete, you specify a final function to be called.
// 1st para in async.each() is the array of items async.each(items, // 2nd param is the function that each item is passed to function(item, callback){ // Call an asynchronous function, often a save() to DB item.someAsyncCall(function (){ // Async call is done, alert via callback callback(); }); }, // 3rd param is the function to call when everything's done function(err){ // All tasks are done now doSomethingOnceAllAreDone(); } );
提示:使用命名函数。
代码
您可以在下面找到我使用的代码:
const dbService = require("./../data/databaseService.js"),
apiService = require("./../data/apiService.js"),
express = require("express"),
async = require("async"),
router = express.Router();
router.get("/list", (req, res, next) => {
dbService.getLists((err, data) => {
if (err) {
next(err);
}
else {
let seriesData = [],
apiRequests = [];
for (let listIndex = data.length; listIndex--;) {
let theName = data[listIndex].name;
seriesData.push({
name: theName,
series: []
});
for (let seriesIndex = data[listIndex].series.length; seriesIndex--;) {
let id = data[listIndex].series[seriesIndex];
apiRequests.push({
destinationListName: theName,
tmdbId: id
});
}
}
let apiCall = (apiReq, cb) => {
apiService.request(`tv/${apiReq.tmdbId}?append_to_response=images,similar`, (err, data) => {
if (err) {
next(err);
}
else {
for (let listIndex = seriesData.length; listIndex--;) {
let name = seriesData[listIndex].name;
if (name == apiReq.destinationListName) {
seriesData[listIndex].series.push(data);
cb();
}
}
}
});
},
afterApiCall = (err) => {
if (err) {
next(err);
}
else {
res.send(seriesData);
}
};
async.each(apiRequests, apiCall, afterApiCall);
}
});
});
module.exports = router;