简体   繁体   English

如何使用Node JS中的嵌套/相关API调用从FOR循环结束时捕获结果

[英]How to capture results from end of FOR loop with Nested/Dependent APIs calls in Node JS

This is my first JavaScript & Node project and I am stuck…. 这是我的第一个JavaScript&Node项目,我被困住了。

I am trying to call a REST API that returns a set of Post IDs... and based on the set of retrieved IDs I am trying to call another API that returns details for each ID from the first API. 我试图调用一个REST API,该REST API返回一组帖子ID ...,并基于检索到的ID集,我试图调用另一个API,该API从第一个API返回每个ID的详细信息。 The code uses Facebook API provided by Facebook-NodeSDK. 该代码使用Facebook-NodeSDK提供的Facebook API。

The problem I am having is that the second API fires of in a FOR Loop…. 我遇到的问题是在FOR循环中触发了第二个API。 As I understand the for loop executes each request asynchronously…. 据我了解,for循环异步执行每个请求……。 I can see both the queries executing however I can't figure out how to capture the end of the second for loop to return the final result to the user… 我可以看到两个查询都在执行,但是我无法弄清楚如何捕获第二个for循环的末尾以将最终结果返回给用户……

Following is the code… 以下是代码…

exports.getFeeds = function(req, res) {

    var posts = [];
    FB.setAccessToken(’SOME TOKEN');
    var resultLength = 0;


     FB.api(
        //ARG #1 FQL Statement
        'fql', { q: 'SELECT post_id FROM stream WHERE filter_key = "others"' },
        //ARG #2 passing argument as a anonymous function with parameter result
        function (result)
           {

               if(!result || result.error) {
                    console.log(!result ? 'error occurred' : result.error);
                    return;
                } //closing if handling error in this block

                    var feedObj
                    console.log(result.data);
                    console.log(result.data.length);

                        for (var i = 0; i<resultLengthj ; i++) {

                        (function(i) {
                            feedObj             = {};
                            FB.api( result.data[ i].post_id,  { fields: ['name', 'description', 'full_picture' ] },
    //                          fbPost is data returned by query
                                function (fbPost) {
                                    if(!fbPost || fbPost.error) {
                                        console.log(!fbPost ? 'error occurred' : result.error);

                                        return;
                                    }
    //                                else
                                        feedObj=fbPost;
                                        posts.push(feedObj);
                            });
                       })(i);
                    }// end for

           }//CLOSE ARG#2 Function

    );// close FB.api Function

NOTE I need to call…... res.Send(post)…. 注意我需要打电话给...... res.Send(post)...。 and have tried to call it at several places but just can't get all the posts… I have removed the console statements from the above code…which have shown that the data is being retrieved... 并尝试在多个位置调用它,但无法获取所有帖子……我从上面的代码中删除了控制台语句……这表明正在检索数据……

Thanks a lot for your help and attention.... 非常感谢您的帮助和关注。

If you just stick res.send almost anywhere in your code, it will be certain to get called before your posts have returned. 如果您只在代码中的几乎任何位置粘贴res.send,那么一定会在帖子返回之前被调用。

What you want to do in a case like this is to declare a counter variable outside your for loop and set it to zero. 在这种情况下,您要做的是在for循环外声明一个计数器变量并将其设置为零。 Then increment it inside the for loop. 然后在for循环中增加它。 Then inside your inner callback (in your case, the one that is getting called once for each post), you would decrement the counter and test for when it hits zero. 然后在内部回调中(对于您的情况,每个帖子被调用一次),您将减少计数器并测试计数器何时为零。 Below I apply the technique to an edited version of your code (I didn't see what feedObj was actually doing, nor did I understand why you were using the immediately-invoked function, so eliminated both - please let me know if i missed something there). 下面,我将该技术应用于您的代码的编辑版本(我看不到feedObj实际在做什么,也不了解您为什么使用立即调用的函数,因此消除了两者-请让我知道是否错过了一些事情那里)。

var posts = [];
FB.setAccessToken(’SOME TOKEN');
var resultLength = 0;


FB.api(
    //ARG #1 FQL Statement
    'fql', { q: 'SELECT post_id FROM stream WHERE filter_key = "others"' },
    //ARG #2 passing argument as a anonymous function with parameter result
    function (result)
    {

        if(!result || result.error) {
            return;
        } //closing if handling error in this block

        var counter = 0;
        for (var i = 0; i<resultLengthj ; i++) {

            counter++;
            FB.api( result.data[ i].post_id,  { fields: ['name', 'description', 'full_picture' ] },
                function (fbPost) { // fbPost is data returned by query
                    if(!fbPost || fbPost.error) {
                        return;
                    }
                    posts.push(fbPost);
                    counter--;
                    if (counter === 0){
                        // Let's render that page/send that result, etc
                    }
                });

        }// end for

    }//CLOSE ARG#2 Function

);// close FB.api Function

Hope this helps. 希望这可以帮助。

Essentially you are wanting to do an async map operation for each id. 本质上,您想对每个id进行异步map操作。

There is a really handy library for doing async operations on collections called async that has a async.map method. 有一个非常方便的库,用于对名为async集合执行异步操作,该库具有async.map方法。

var async = require('async'); 

FB.api(
    'fql', { q: 'SELECT post_id FROM stream WHERE filter_key = "others"' },
    //ARG #2 passing argument as a anonymous function with parameter result
    function (result) {

        async.map(
            result,

            function (item, callback) {
                FB.api(
                    item.post_id, 
                    { fields: ['name', 'description', 'full_picture' ] }, 
                    callback
                );
            },

            function (err, allPosts) {
                if (err) return console.log(err);

                // Array of all posts
                console.log(allPosts);
            }
        );

    }
);

You definitely don't need to use this, but it simplifies your code a bit. 您绝对不需要使用它,但是它可以稍微简化您的代码。 Just run npm install --save async in your project directory and you should be good to go. 只需运行npm install --save async在项目目录中保存npm install --save async ,就可以了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM