由于Node的异步性质,需要协助解决问题

时间:2015-05-20 17:03:13

标签: javascript node.js asynchronous

鉴于Node的异步特性,我无法弄清楚如何完成我正在尝试的内容。从概念上讲,我想这样做:

  1. 使用Twitter API运行搜索
  2. 对结果推文进行迭代,以便使用运行情绪检查 alchemylab的api - 每条推文及其相关的情绪信息 被推到阵列
  3. 渲染页面,然后循环显示数组 推文和情绪信息
  4. 这是我的代码:

    
    
        client.get('search/tweets', {q: 'node.js'}, function(error, tweets, response)
        {
            for (var i=0; i<tweets.statuses.length; i++){
               var ttext = tweets.statuses[i].text;
               var tsrc = tweets.statuses[i].source;
               var lang = '';
               var sentiment = '';
               var score = '';
    
               var tweet = {
                             text: tweets.statuses[i].text,
                             source: tweets.statuses[i].source
                           };
              
               alchemyapi.sentiment("text", ttext, {}, function(response) {
     
                  if (response.status == 'OK' ){
                    tweet.lang = response.language;
                    tweet.sentiment = response['docSentiment'].type;
                    tweet.score = response['docSentiment'].score;
                    console.log("pushing: " + util.inspect(tweet) );
                    tweet_data.push( tweet );
                  }
    
               });
    
            }
    
            
    
            res.render('twitter', {
                myText: myText,
            });
        });
    &#13;
    &#13;
    &#13;

    正在发生的事情是在任何alchemyapi调用完成之前呈现的页面。我很想思考 异步术语和避风港已经完全绕过它。

    非常感谢任何帮助!

    谢谢, 安迪

    编辑 -

    我正在尝试使用Promises实现延迟方法而且没有太多运气..我现在已经将parseTweet定义为您建议的函数,如果响应是&#39; OK&#39;它调用resolve(tweet) - 不确定这是否正在做任何事情。我的for()循环现在看起来像这样:

    &#13;
    &#13;
                promises.push(parseTweet(tweets.statuses[i]));
    
                Promise.all(promises).then(function(){
                    console.log('all promises complete');
                }, function(){
                    console.log('error occurred with promises');
                });
     
    &#13;
    &#13;
    &#13;

    我在parseTweet函数中有注释,我看到所有的推文都被解析但不在Promise.all块中 - 并且程序永远不会完成,一直运行直到我杀了它......

2 个答案:

答案 0 :(得分:1)

好的,函数“alchemyapi.sentiment”是异步的,你正在调用很多次,完全是“tweets.statuses.length”,并且在代码的末尾你调用函数“res.send”所以你在“for loop”结束之前调用此函数,因此,这是我的解决方案(伪代码):

1)创建一个接收推文的函数,创建推文数据(你的逻辑+ alchemyapi.sentiment)。此函数返回一个javascript承诺(在我的示例中,我将使用jquery defer编写更少的代码,但您可以使用本机承诺):

function parseTweet(tweet) {
        $promise = $.defer();
        var tweetDataObject = {}; // this is not important, put your required data

        // call alchemyapi async
        alchemyapi.sentiment("text", ttext, {}, function(response) {
            if (response.status == 'OK' ) {
                // parse data and "return" valid object
                $promise.resolve(tweetDataObject);
            } else { // data is not valid, return null
                $promise.reject(null); // null, empty object, what you need
            }
        }); 

        return $promise;
    }

2)在你的main方法上,执行for循环,调用函数parseTweet(返回类似promise的内容)并等待所有promise:

var promises = [];
for (var i=0; i<tweets.statuses.length; i++) {
    promises.push(parseTweet(tweets.statuses[i]));

    $.when(promises).then(function() {
        // here, on "arguments" you have array of objects that parseTweet "return" when called resolve or reject

        console.log(arguments);
    });
}

我使用jquery defer编写了这个例子,但是使用本机承诺很容易(特别是在这种情况下,我们有许多承诺等待$ .when函数)。

请仔细阅读这篇文章:http://www.html5rocks.com/en/tutorials/es6/promises/

更新:示例

我在github上做了一个例子。如果您有疑问请告诉我,但我认为这很清楚 https://github.com/josemato/stackoverflow/tree/master/es-promise-all-no-order

答案 1 :(得分:0)

使用vert.x很容易:当请求事件进入时,将其推迟到工作模块并让它执行长时间运行的处理。注册处理“all finished”事件的处理程序以进行显示。

也许这个过程也适用于node.js:让长时间运行的炼金术调用一个单独的线程,在完成后注册“全部完成”事件。要求UI在收到该事件时使用回调注册自己。