让Node等待所有数据加载以发送响应

时间:2016-12-11 14:57:51

标签: node.js express asynchronous wait

情况草图

我正在制作一个带有的Node.js的网络服务器。我将把一些系列表示在我的Android应用程序的主片段列表中。如下图所示:

a list is an array of series

红色矩形是一个包含多个系列的列表。

数据

在数据库中,我创建了一个名为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加载所有数据?如果是的话,为什么呢?

另请注意,列表中的项目必须相同。示例:系列“权力的游戏”位于美国列表中,无法推送到其他列表。同样的系列“Als de dijken breken”。这个系列站在弗拉芒语列表中,不能被推入英国。

参考

我已经创建了一个图像,您可以在其中再次检查代码,并将每个请求和响应的结果作为JSON代码获得。

Reference (点击图片查看实际尺寸)

1 个答案:

答案 0 :(得分:0)

经过搜索和测试,我终于找到了解决方案。

图书馆

对于图书馆,我使用Async.js。您可以在命令行中使用以下代码安装它:

npm install --save async

使用此

添加了库
const async = require("async");

我使用async.each()方法。

  

这是解决问题的简单方法。该函数接受一个项目数组,然后迭代它们调用一个包装函数,该函数接受该项作为参数。完成所有调用后,指定要调用的最终函数。

// 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();
  }
);
     

来源:justinklemm.com - Node.js Async tutorial

提示:使用命名函数。

代码

您可以在下面找到我使用的代码:

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;