【问题标题】:TypeError: Cannot read property 'latestTimestamp' of undefined [duplicate]TypeError:无法读取未定义的属性“latestTimestamp”[重复]
【发布时间】:2014-09-07 04:27:42
【问题描述】:

我发现了很多类似的问题,但我仍然不知道我的代码有什么问题。似乎我无法在回调函数中读取全局变量值(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)

【问题讨论】:

  • 这是一个困扰 JavaScript 程序员的非常常见问题的实例,并且经常以这种形式出现 - 使用索引变量的循环,以及为异步函数设置回调的循环中的代码它本身使用索引变量。
  • 你可以检查这个问题stackoverflow.com/questions/13343340/…并完全删除你的问题。
  • 了解该错误的基本表面含义也很重要:当您看到它时,这意味着 .latestTimestamp 左侧的内容实际上并不是对对象的引用,正如代码所期望的那样- 它是undefined。因此,找出问题的第一步是在代码中查找此类引用。
  • @vishwanath 是的,一个和任何一个一样好。但是,我认为不应该删除这个。封闭的问题仍然可以搜索,这可能会帮助一些未来的程序员找到答案。

标签: javascript


【解决方案1】:

扩展@Pointy 在您帖子下的评论中所说的话:

您在 MongoDB 中使用的插入函数是异步的,但您将回调视为同步的。在您的循环中本质上发生的事情是,在您点击 collection.insert 之前,一切都按计划进行。从那里,该过程中断并基本上说“我要告诉 mongo 现在插入一条记录......最终我会期待回应。”同时,循环继续到下一个索引,并且不会同步等待回调触发。

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

我建议您重新设计循环以支持节点的异步特性。有一个很棒的库叫做 - 奇怪的是 - async,它让这个过程变得超级简单。 async.each() 函数应该可以帮助您完成您正在尝试做的事情。

【讨论】:

  • 哦,是的,我什至没有看到.insert() 电话;我认为这是对“feed()”的回调。然而,同样的基本问题。
【解决方案2】:

这可能应该作为重复关闭,但我会在这里给出一个答案,因为对于没有理解基本问题的 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
     };
   }

然后你会这样称呼“饲料”:

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

关键的区别在于,传递给“feed”的每个函数都有自己的来自“urls”数组的对象的私有副本(嗯,引用的副本很挑剔),所以它不需要完全参考变量“j”。这就是问题的症结所在:“j”被代码中的所有回调共享。在调用回调时,“j”的值等于“urls”数组的长度,所以urls[j]undefined

其他方法是使用.forEach 方法,在较新的JavaScript 实现中可用。这种方法将完全摆脱“j”:

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

再次确保发送到“feed”函数的每个回调都有自己的“urls”元素副本。

【讨论】:

  • 我可能错了,有点跑题了,但是如果feedthis modul,那么第一个参数应该是字符串(url),不是urls[j],而是@987654331 @?与问题本身无关,我只是好奇。
  • @Windkiller 是的可能;我很惊讶它在原始代码中所做的那样。我想“feed”功能可能知道该怎么做。
猜你喜欢
  • 2021-03-18
  • 2017-12-15
  • 1970-01-01
  • 2019-08-19
  • 2017-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多