【问题标题】:Javascript Cannot read property 'forEach' of undefined after fetch提取后Javascript无法读取未定义的属性'forEach'
【发布时间】:2020-12-18 00:30:09
【问题描述】:

我尝试查看其他问题,但找不到合适的解决方案。我正在检索一个 GET 响应并将其存储到一个变量中,然后我解析该数组以查找每日发生的事件。该代码有效,但一旦到达 forEach 就会抱怨:

Cannot read property 'forEach' of undefined

。这是我的代码:

var myObj;
fetch('https://blashblashblash.com?param1')
.then(res=>res.json())
.then(data=>myObj= data)
.then(() => console.log(myObj));

var myRes = [];

myObj.forEach(function (elem) {
    var date = elem.CreationDate.split(' ')[0];


    if (myRes [date]) {
        myRes [date] += 1;
    } else {
        myRes [date] = 1;
    }
});

这就是 myObj 完成后的内容:

[{Id, Var1, Var2, CreationDate},
{1, 123, Var2, 2020-12-11},
{2, 1234, Var2, 2020-12-12},
{3, 12345, Var2, 2020-12-12},
{4, 1234, Var2, 2020-12-13},
{5, 321, Var2, 2020-12-15},
{6, 3214, Var2, 2020-12-15},
{7, 5432, Var2, 2020-12-16}]

我哪里错了?如果我在不同的步骤中执行代码,它可以正常工作。

编辑: 这是我更新的代码:

var myObj;
var myRes= [];
fetch('https://blashblashblash.com?param1')
.then(res=>res.json())
.then(data=>myObj= data)
.then(() => {
myObj.forEach(function (elem) {
    var date = elem.CreationDate.split(' ')[0];
    if (myRes[date]) {
        myRes[date] += 1;
    } else {
        myRes[date] = 1;
    }
});

});

var finalResult= {};
dates.forEach(date => {
    if(!myRes.hasOwnProperty(date)) {
        finalResult[date] = 0;
    } else {
        finalResult[date] = myRes[date];
    }
    return finalResult;
});

如果我正在执行整个我的 finalResult 是空的,而如果我在块中执行它它可以工作。如果我将 myRes =[] 插入最后一个 . 然后它抱怨它找不到它。我哪里错了?

【问题讨论】:

  • 您不能从这样的提取中返回数据。要么把所有依赖 myObj 的东西放在 then 中,要么使用 aysnc/await。
  • 但如果我分两步执行代码,这将正常工作。我该如何解决?
  • @evolutionxbox 我试过了,但我不明白如何解决。检索到其中的值后,需要对该对象执行一些操作
  • 你可以。要么在附加的 then 中执行操作,要么等待 fetch。

标签: javascript arrays foreach


【解决方案1】:

编辑

重复:您可能更喜欢this answer

编辑:从then() 外部访问响应

简答:

你不能。

长答案:

你正在做的是一个异步操作。这意味着我们不知道需要多长时间。

给定下面的示例代码,假设fetch() 需要 5 秒才能完成。

fetch('https://blashblashblash.com?param1').then(doOtherThings);

someTaskAfterFetch();

console.log('Done');

运行此代码后,需要多长时间才能在控制台中看到“完成”?答案是立即

发生了什么?

让我们看看会发生什么。

    ===       fetch(url).then(doOtherThings) --> 'Start' fetching, without waiting for result.
     |               |
     |               |                       --> You expect fetch to be done here, which will not happen.
     |               |
     |        someTaskAfterFetch()           --> At this moment you see no fetch result.
almost 0 sec         |
     |               |
     |        console.log('Done')
     |               |
    ===       'Done' is printed
     |               |
     |               |
about 5 sec   (in some future)
     |               |
     |               |
    ===       **Fetch completed**             --> Fetch is finished here.
                     |
              doOtherThings(result)           --> doOtherThings, which we passed to `then()` will be run here.

执行从第 1 行的fetch(url).then(doOtherThings) 开始。

然后立即在第 2 行继续someTaskAfterFetch()

之后,移动到console.log('done')

在不久的将来(大约 5 秒后),您开始的 fetch 终于完成,并使用结果调用 doOtherThings

结果如何处理?

在考虑异步任务时,您必须将调用等待分开。您通过调用 fetch() 启动了一个 fetch 任务,但没有等待结果。

处理获取结果:

  • 您可以等到任务完成(async/await)
  • 或者告诉提取完成后要做什么。

使用then() 是第二种方法。您可以将所有结果处理代码传递给then()

如需更详细的答案,您可能喜欢this


在您的代码中,

fetch('https://blashblashblash.com?param1')
.then(res=>res.json())
.then(data=>myObj= data)
.then(() => console.log(myObj));

此行将立即返回。

紧接着,

myObj.forEach(function (elem) {
    var date = elem.CreationDate.split(' ')[0];


    if (myRes [date]) {
        myRes [date] += 1;
    } else {
        myRes [date] = 1;
    }
});

forEach 将被调用。

此时,请求获取作业forEach 之前很快完成。但是,获取本身可能当时还没有完成。

您传递给以下then() 调用的函数将在获取成功完成后启动。

您可以将forEach 代码传递给then() 方法:

var myObj;
fetch('https://blashblashblash.com?param1')
.then(res => res.json())
.then(data => myObj = data)
.then(() => console.log(myObj));
.then(() => {
    var myRes = [];

    myObj.forEach(function (elem) {
        var date = elem.CreationDate.split(' ')[0];


        if (myRes [date]) {
            myRes [date] += 1;
        } else {
            myRes [date] = 1;
        }
    });

    // And other stuffs to do with myRes.
})

【讨论】:

  • 这是stackoverflow.com/questions/14220321/… 的重复项,您可以这样标记吗?
  • 用问题更新了我的问题
  • @Potados 如何从外部访问我的变量?就像我在编辑中描述的那样
  • 非常感谢!我使用setTimeout() 解决了
  • @thranduil90 只会掩盖问题。当获取时间超过超时时间时,它将失败。
【解决方案2】:

由于您的 fetch & then 是异步操作,因此您需要在 then 函数中执行 forEach,如下所示:

var myObj;
fetch('https://blashblashblash.com?param1')
.then(res=>res.json())
.then(data=>myObj= data)
.then(() => {
    console.log(myObj);
    var myRes = [];

    myObj.forEach(function (elem) {
        var date = elem.CreationDate.split(' ')[0];


        if (myRes [date]) {
            myRes [date] += 1;
        } else {
            myRes [date] = 1;
        }
    });
});

【讨论】:

  • 这是stackoverflow.com/questions/14220321/… 的副本。请问可以这样标记吗?
  • 谢谢!但是我需要访问 myRes 元素,在这种情况下,它说它没有定义。之后如何访问它?
  • @thranduil90 您可以在then(() => { ... }) 块中访问myRes
  • @thranduil90 不在then之外你不能。
  • 我可以在 myObj 附近声明它然后访问它吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多