TypeError:无法读取属性' latestTimestamp'未定义的

时间:2014-07-16 15:05:02

标签: javascript

我发现了很多类似的问题,但我仍然不知道我的代码有什么问题。似乎我无法在回调函数中读取全局变量值(urls):我想更新回调函数中的urls latestTimestamp值(错误,文章)。这是出错的代码:

var urls=[
    {"url": "http://www.economist.com/feeds/print-sections/77/business.xml", "latestTimestamp": new Number(0)},
    {"url": "http://news.sky.com/feeds/rss/home.xml", "latestTimestamp": new Number(0)},
    ]; // Example RSS Feeds; 

// parse RssFeeds from given websites and write them into databse
function parseRssFeeds(collection){
    var feed = require('feed-read');  // require the feed-read module

    // loop through our list of RSS feed urls
    for (var j = 0; j < urls.length; j++)
    {
        console.log('Original url timestamp is: '+ urls[j].latestTimestamp.toString());

        // fetch rss feed for the url: 
        feed(urls[j], function(err, articles)
        {
            // loop through the list of articles returned
            for (var i = 0; i < articles.length; i++)
            {           
                var message = 
                    {"title": articles[i].title,
                     "link": articles[i].link,
                     "content": articles[i].content,
                     "published": articles[i].published.getTime()};

                collection.insert(message, {safe:true}, function(err, docs) {
                    if (err) {
                        console.log('Insert error: '+err);
                    }else{
                        console.log('This item timestamp is: '+ message.published);
                        // get the latest timestamp
                        if (message.published >urls[j].latestTimestamp) {
                            console.log('update timestamp to be: '+ message.published);
                            urls[j].latestTimestamp = message.published;
                        }   
                    }
                });// end collection insert         
            } //  end inner for loop
        }) // end call to feed method

    } // end urls for loop
}

感谢您的帮助。错误是:

TypeError: Cannot read property 'latestTimestamp' of undefined
    at /Users/Laura/Documents/IBM/project/TestList/app.js:244:37
    at /Users/Laura/Documents/IBM/project/TestList/node_modules/mongodb/lib/mongodb/collection/core.js:123:9
    at /Users/Laura/Documents/IBM/project/TestList/node_modules/mongodb/lib/mongodb/db.js:1131:7
    at /Users/Laura/Documents/IBM/project/TestList/node_modules/mongodb/lib/mongodb/db.js:1847:9
    at Server.Base._callHandler (/Users/Laura/Documents/IBM/project/TestList/node_modules/mongodb/lib/mongodb/connection/base.js:445:41)
    at /Users/Laura/Documents/IBM/project/TestList/node_modules/mongodb/lib/mongodb/connection/server.js:478:18
    at MongoReply.parseBody (/Users/Laura/Documents/IBM/project/TestList/node_modules/mongodb/lib/mongodb/responses/mongo_reply.js:68:5)
    at null.<anonymous> (/Users/Laura/Documents/IBM/project/TestList/node_modules/mongodb/lib/mongodb/connection/server.js:436:20)
    at emit (events.js:95:17)
    at null.<anonymous> (/Users/Laura/Documents/IBM/project/TestList/node_modules/mongodb/lib/mongodb/connection/connection_pool.js:201:13)

2 个答案:

答案 0 :(得分:1)

这应该可以作为副本关闭,但我会在这里给出答案,因为所有重复问题之间的关系通常很难掌握,因为JavaScript程序员还没有理解基本问题。

有两种方法可以解决这个问题。一种方法是更改​​创建回调的方式。而不是使用内联匿名函数:

    feed(urls[j], function(err, articles)
    {
        // loop through the list of articles returned
        // ...

您要创建另一个返回回调的功能。您将该功能传递给URL,以及返回的功能将使用的内容:

   function makeFeedResultHandler(url) {
     return function(err, articles) {
       // loop through the list of articles returned
       // ... code as before up to this line:
                    if (message.published > url.latestTimestamp) {
                        console.log('update timestamp to be: '+ message.published);
                        url.latestTimestamp = message.published;
                    }   
       // ... etc
     };
   }

然后你拨打#34; feed&#34;像这样:

   feed(urls[j], makeFeedResultHandler(urls[j]));

关键的区别在于每个函数都传递给&#34; feed&#34;将从&#34; urls&#34;拥有自己的对象私有副本(以及引用的副本)。数组,所以它不需要引用变量&#34; j&#34;一点都不这就是问题的症结所在:&#34; j&#34;您的代码中的所有回调都是共享。在调用回调时,&#34; j&#34;的值。等于&#34; urls&#34;的长度。数组,因此urls[j]undefined

其他方法是使用.forEach方法,可在较新的JavaScript实现中使用。这种方法将摆脱&#34; j&#34;共:

  urls.forEach(function(url) {
    console.log('Original url timestamp is: '+ url.latestTimestamp.toString());

    // fetch rss feed for the url: 
    feed(url, function(err, articles)
    {
        // loop through the list of articles returned
        // ... code as previously, substituting "url" for "urls[j]" everywhere
    });
 });

再一次,确保每个回调都发送到&#34; feed&#34;函数有自己的&#34; urls&#34;元件。

答案 1 :(得分:1)

扩展@Pointy在你发表的评论中所说的内容:

您与MongoDB一起使用的插入函数是异步的,但您正在将回调视为同步。你的循环中发生了什么,一切都按计划进行,直到你遇到collection.insert。从那里开始,这个过程就中断了,基本上就是说我现在要告诉mongo插入一条记录......最终我会期待一个回应。&#34;同时,循环继续到下一个索引,并且不会同步等待直到回调触发。

当您的回调触发时,您的循环已经完成,并且J不再代表索引,这就是它未定义的原因。您还冒着获得与此计划不同的索引的风险。

我建议您重新设计循环以支持节点的异步性质。有一个很棒的图书馆 - 奇怪的是 - async让这个过程变得非常简单。 async.each()函数可以帮助您完成您要完成的任务。