变量可能超出范围

时间:2018-04-09 19:46:15

标签: javascript html css node.js electron

虽然代码起初可能看起来有点沉重(可能无论如何),但它有点简单。我想要做的就是从JSON文件中读取一些数据(格式如下:

{"news":[{}]}


,并将一些信息推送到我从另一个来自newsapi.org服务器的JSON文件中获取的数组中。我的问题可能是由吊装造成的,但我不知道如何解决它..!在控制台中,它会吐出Uncaught TypeError: Cannot read property 'title' of undefined

以下内容是我已失效代码的摘录。

(我知道我的代码看起来很乱:P)

function appendNews(id) {
    var xhr = new XMLHttpRequest();
    xhr.open("GET", "https://newsapi.org/v2/top-headlines?sources=" + id +
        "&apiKey=8fdd732e76664e06b177a20fb295129c", true);
    xhr.send();
    xhr.addEventListener("readystatechange", processRequest, false);
    xhr.onreadystatechange = processRequest();

    function processRequest() {
        if (xhr.readyState == 4 && xhr.status == 200) {
            var response = JSON.parse(xhr.responseText);
            var container = document.getElementById("newsContainer");
            for (var i = 0; i < response.articles.length; i++) {
                fs.readFile('./data/events/news.json', 'utf8', function(err, data) {
                    if (err) {
                        console.log(err)
                    } else {
                        var file = JSON.parse(data)
                        file.news.push({
                            "title": response.articles[i].title,
                            "description": response.articles[i].description,
                            "url": response.articles[i].url,
                            "urlImg": response.articles[i].urlToImage,
                            "time": response.articles[i].publishedAt,
                            "sourceAndAuthor": response.articles[i].author + " (" +
                                response.articles[i].source.name + ")"
                        })
                        var toStringify = JSON.stringify(file);
                        fs.writeFile('./data/events/news.json', toStringify, 'utf8', function(err) {
                            if (err) {
                                console.log(err);
                            } else {

                            }
                        });
                    }
                });
            }
        }

编辑:在我的代码中,我使用相同的变量,然后它可以工作:

var holder = document.createElement("button");
holder.setAttribute("id", "newsHolder");
holder.setAttribute("onclick", "openArticle(" + "'" + 
response.articles[i].title + "'" + ")")

var title = document.createElement("div");
title.setAttribute("id", "newsTitle");
title.innerHTML = response.articles[i].title;
var image = document.createElement("img");
image.setAttribute("src",response.articles[i].urlToImage)
image.setAttribute("id", "articleImage");
holder.appendChild(title);
holder.appendChild(image);
container.appendChild(holder);
fadeIn("newsContainer",1,0.01,1);

1 个答案:

答案 0 :(得分:1)

这是您的控制流程中的一个主要问题:

for (var i = 0; i < response.articles.length; i++) {
  fs.readFile('./data/events/news.json', 'utf8', function(err, data) {
    ...
    var file = JSON.parse(data)
    ...
    var toStringify = JSON.stringify(file);

    fs.writeFile('./data/events/news.json', toStringify, 'utf8', function(err) {

    });
  });
}

这样的写作表明完全缺乏对异步编程的理解,因为真正最终发生的是竞争条件,其中最后一次成功fs.writeFile()只会将response.articles中的一个条目附加到您的JSON,即使您要修复TypeError

您希望代码能够像这样运行:

i=1    2    3    4    5 ... L
   r    r    r    r    r
    p    p    p    p    p
     w    w    w    w    w

r, p, w分别代表fs.readFile()file.news.push()fs.writeFile(),但真正发生的是:

i=1 2 3 4 5 ... L
                 r r r r r ...
                               p   p  p    p  p ...
                                 w   w  w    w  w ...

您的推送和写入将以无保证的顺序发生,它们不一定是顺序的。

其中Lreseponse.articles.length,并且您在response.articles[i]时尝试访问i === response.articles.length,因此当然不存在article。< / p>

第一个改变是使用

for (let i = 0; i < response.articles.length; i++) {

但是这不会解决上面解释的竞争条件,它只会导致i具有词法范围,所以至少你不会访问越界。

为了避免不必要的阅读和写作,您只需fs.readFile()一次,循环浏览articles并将其推送到回调中的file.news,然后fs.writeFile()for循环结束后。这看起来像这样:

// add your event listener BEFORE sending
xhr.addEventListener('load', processRequest, false);
xhr.send();

function processRequest() {
  // no need to check readyState and status if you use the `load` event
  fs.readFile(..., (err, data) => {
    // handle error
    if (err) {
      console.log(err);
      return;
    }

    const { articles = [] } = JSON.parse(xhr.responseText);
    const file = JSON.parse(data);

    for (const article of articles) {
      const {
        title,
        description,
        url,
        urlToImage: urlImg,
        publishedAt: time,
        author,
        source: { name }
      } = article;

      file.news.push({
        title,
        description,
        url,
        urlImg,
        time,
        sourceAndAuthor: `${author} (${name})`
      });
    }

    const json = JSON.stringify(file);

    fs.writeFile(..., (err) => {
      if (err) {
        console.log(err);
        return;
      }
    });
  });
}