无法读取未定义的属性“长度” ...尽管对象已定义

时间:2020-02-21 01:23:36

标签: javascript

首先,我有以下代码部分:

export default class Recipe {
  constructor(recID) {
    this.RecipeID = recID;
  }

  async GetRecipe() {
    try {
      let Result = await Axios(
        `https://forkify-api.herokuapp.com/api/get?rId=${this.RecipeID}`
      );
      this.Tilte = Result.data.recipe.title;
      this.Author = Result.data.recipe.publisher;
      this.Image = Result.data.recipe.image_url;
      this.Url = Result.data.recipe.source_url;
      this.Ingredients = Result.data.recipe.ingredients;
      this.PublisherUrl = Result.data.recipe.publisher_url;
      this.Rank = Result.data.recipe.social_rank;
    } catch (error) {
      alert(error);
    }
  }

  CalculateTime() {
    try {
      this.Time = Math.ceil(this.Ingredients.length / 3) * 15; // error is here
    } catch (error) {
      console.log(this.RecipeID + ": Length Error->"+error);
    }
  }
}

然后我将上述代码放在一个单独的文件中,例如:

import Recipe from "./Recipe";

const RecipeController = async () => {
  const ID = window.location.hash.replace("#", "");

  if (ID) {
    AppState.Recipe = new Recipe(ID);

    try {
      await AppState.Recipe.GetRecipe();

      AppState.Recipe.CalculateTime();

      console.log(AppState.Recipe);
    } catch (error) {
      alert(error);
    }
  }
};

现在,如下图所示,我确实获得了请求的响应并答应了,并且在“成分”数组中有元素,但是有时我仍然收到错误“无法读取未定义的属性'length'当我调用'CalculateTime()'时,尽管现在已经定义了数组,有时我没有收到任何错误,并且工作得很好。为什么这种随机行为呢?甚至JSON响应中的ID和我记录的错误也都匹配,即47746。 enter image description here

3 个答案:

答案 0 :(得分:1)

这是为什么有太多try / catch可以掩盖错误原因,使调试困难的原因之一。该问题可以归结为以下内容:

class Recipe {
  constructor(recID) {
    this.RecipeID = recID;
  }
  async GetRecipe() {
    let Result = await fetch(
      `https://forkify-api.herokuapp.com/api/get?rId=47746`
    ).then(res => res.json());
    console.log(Result); // <----- look at this log
    this.Tilte = Result.data.recipe.title;
    // on the above line, the error is thrown
    // Cannot read property 'recipe' of undefined
  }
}
const r = new Recipe();
r.GetRecipe();

请参阅日志:您的Result对象没有.data属性,因此引用Result.data.recipe会引发错误。尝试使用Result.recipe

class Recipe {
  constructor(recID) {
    this.RecipeID = recID;
  }
  async GetRecipe() {
    let Result = await fetch(
      `https://forkify-api.herokuapp.com/api/get?rId=47746`
    ).then(res => res.json());
    const { recipe } = Result;
    this.Tilte = recipe.title;
    this.Author = recipe.publisher;
    this.Image = recipe.image_url;
    this.Url = recipe.source_url;
    this.Ingredients = recipe.ingredients;
    this.PublisherUrl = recipe.publisher_url;
    this.Rank = recipe.social_rank;
  }

  CalculateTime() {
    this.Time = Math.ceil(this.Ingredients.length / 3) * 15; // error is here
    console.log('got time', this.Time);
  }
}
(async () => {
  const r = new Recipe();
  await r.GetRecipe();
  r.CalculateTime();
})();

除非您实际上可以在特定点处处理错误,否则通常允许该错误向上渗透到调用方,以便调用方可以看到存在错误并进行处理,这通常是很好的。考虑更改原始代码,以便RecipeController(并且只有RecipeController)可以看到错误并进行处理-您可以从{{1}中删除try / catch }}。

答案 1 :(得分:0)

您确定某些回复中没有缺少成分吗?而且总是在getRecipe之后调用calculateTime吗?

我将添加条件或后备以防止发生错误,例如。

 this.Time = Math.ceil((this.Ingredients || []).length / 3) * 15; 

答案 2 :(得分:0)

我推测这种“随机”行为可能与异步代码有关。在计算之前,您需要确保该类具有适当的成分。我有一种感觉,您应该尝试使用.then().catch()将语法更改为Promise handling,尤其是因为您已经在代码中使用try/catch了。这种方法将确保在axios请求上正确解决Promise,并消除“随机性”,因为您将更好地控制Promise处理的不同阶段。

let Result = await Axios(
        `https://forkify-api.herokuapp.com/api/get?rId=${this.RecipeID}`
       )
       .then((data) => {
           this.Tilte = data.data.recipe.title;
           this.Author = data.data.recipe.publisher;
           this.Image = data.data.recipe.image_url;
           this.Url = data.data.recipe.source_url;
           this.Ingredients = data.data.recipe.ingredients;
           this.PublisherUrl = data.data.recipe.publisher_url;
           this.Rank = data.data.recipe.social_rank;
           this.Ingerdients = data.data.recipe.ingredient;
       }
       .catch((err) => {
           console.log(err);
           return null;
       });