在JS类中处理异步数据

发布于 2025-02-05 10:45:05 字数 1175 浏览 1 评论 0原文

目标:我想建立一个解决新闻接口并在视图中呈现数据的类。 我的类(myNews)有几种方法,一种方法是fetchnews()。在这种方法中,我从API获取数据。来自API的数据应在类Varaible(News)中分配。在另一种方法中(exhingews()),我想访问数据以迭代它。

我的问题:我是JS的初学者,我想知道如何查询数据。从我的理解来看,流是这样的: 构造函数调用fetchnews Fetch News首先得到承诺,等到解决诺言得到解决 然后将数据分配给会员 但是JS Async正在运行JS,此时不再等到承诺得到解决,并且继续使用空数组。这正是我的问题。

问题我需要做什么或更改以正确获取数据。这样我就可以构建一个HTML列表。

我的JS代码

class MyNews {
  news = [];
  
  apiUrl = "https://jsonplaceholder.typicode.com/posts";
  
  constructor() {
    this.news;
    this.fetchNews();
  }
  
  fetchNews() {
    fetch(this.apiUrl)
      .then(async (data) => {
        this.news = await data.json(); 
        console.log("A:",this.news.length); // i have results
      })
      .catch((err) => {
        console.log(err)
      });
                // ...
  }
  
  showNews() {
    console.log("B:",this.news.length); // empty array
    
    return this.news;
  }
}
    

n = new MyNews;
console.log("C:", n.showNews().length );

Goal: I want to build a class that addresses a news interface and renders the data in the view.
My class (MyNews) has several methods and one method is fetchNews(). In this method I get the data from the API. The data from the api should be assigned in a class varaible (news). In another method (showNews()) I want to access the data to iterate over it.

My problem: I am beginner in js and I wonder how to query the data. From my understanding the flow is like this:
constructor calls fetchNews
fetch news first gets a promise and waits until the promise is resolved
then the data is assigned to the member
but the JS async is running js doesn't wait at this point until the promise is resolved and it continues working with the empty array. This is exactly my problem.

Question What do I need to do or change to fetch the data correctly. So that I can build a HTML list for example.

My JS Code

class MyNews {
  news = [];
  
  apiUrl = "https://jsonplaceholder.typicode.com/posts";
  
  constructor() {
    this.news;
    this.fetchNews();
  }
  
  fetchNews() {
    fetch(this.apiUrl)
      .then(async (data) => {
        this.news = await data.json(); 
        console.log("A:",this.news.length); // i have results
      })
      .catch((err) => {
        console.log(err)
      });
                // ...
  }
  
  showNews() {
    console.log("B:",this.news.length); // empty array
    
    return this.news;
  }
}
    

n = new MyNews;
console.log("C:", n.showNews().length );

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

相思故 2025-02-12 10:45:05

几个问题:

  1. 首先是fetchnews是一个异步过程。在您的示例中,显示的将始终为0,因为fetchnews在调用eashingews时尚未获取任何内容。我们可以通过将这些方法的调用在班级外移动来减轻其中的一些。

  2. 您有fetchasync/等待的奇数混合物 - 最好坚持一个或另一个。

class MyNews {

  apiUrl = 'https://jsonplaceholder.typicode.com/posts';

  // `async/await` function - fetches the JSON, and
  // sets the `news` field to the parsed JSON
  async fetchNews() {
    try {
      const response = await fetch(this.apiUrl);
      if (response.ok) this.news = await response.json();
    } catch (err) {
      this.error = err.message;
    }
  }
  
  formatNews() {
    return this.news.map(n => {
      return `<p>${n.title}</p>`;
    }).join('');
  }
  
  // Return the news or the error if there was one.
  showNews() {
    if (!Array.isArray(this.news)) return this.error;
    return this.formatNews();
  }

}

// Piecing it together we create a new
// object, call and `await` `fetchNews` and
// then call `showNews`
async function main() {
  const myNews = new MyNews();
  await myNews.fetchNews();
  document.body.innerHTML = myNews.showNews();
}


main();
p { border: 1px solid #787878; padding: 0.3em; border-radius: 5px; margin: 0.2em; text-transform: capitalize; }
p:hover { cursor: pointer; background-color: #ffffd0; }

A couple of issues:

  1. The first is that fetchNews is an async process. In your example showNews will always be 0 because fetchNews hasn't fetched anything when showNews is called. We can mitigate some of this by moving the calling of those methods outside of the class.

  2. You have an odd mix of fetch and async/await - it's best to stick with one or the other.

class MyNews {

  apiUrl = 'https://jsonplaceholder.typicode.com/posts';

  // `async/await` function - fetches the JSON, and
  // sets the `news` field to the parsed JSON
  async fetchNews() {
    try {
      const response = await fetch(this.apiUrl);
      if (response.ok) this.news = await response.json();
    } catch (err) {
      this.error = err.message;
    }
  }
  
  formatNews() {
    return this.news.map(n => {
      return `<p>${n.title}</p>`;
    }).join('');
  }
  
  // Return the news or the error if there was one.
  showNews() {
    if (!Array.isArray(this.news)) return this.error;
    return this.formatNews();
  }

}

// Piecing it together we create a new
// object, call and `await` `fetchNews` and
// then call `showNews`
async function main() {
  const myNews = new MyNews();
  await myNews.fetchNews();
  document.body.innerHTML = myNews.showNews();
}


main();
p { border: 1px solid #787878; padding: 0.3em; border-radius: 5px; margin: 0.2em; text-transform: capitalize; }
p:hover { cursor: pointer; background-color: #ffffd0; }

静水深流 2025-02-12 10:45:05

问题在于fetch()是一个异步函数。这就是实际发生的事情:

  1. 构造函数称为
  2. fetchnews是启动
  3. 的构造函数,这可能是在FetchNews
  4. doadeews可能运行之前就

完成的构造函数。但是,这并不能完全解决您的问题,因为构造函数不能成为异步功能。

我建议使用此解决方案:

fetchnews的呼叫移至myNews类上的init方法,并将其变为异步。

class MyNews {
    ...
    async fetchNews() {
        await fetch(...);
    }
    ...
    async init() {
        await fetchNews();
    }
    ...
}
const news = new MyNews();
await news.init();
news.showNews();

您可以在

顺便说一句:this.news;似乎不必要。

The problem is that fetch() is an async function. This is what actually happens:

  1. Constructor is called
  2. fetchNews is started
  3. Constructor probably finishes before fetchNews
  4. showNews probably runs before fetchNews is done

First thing that comes to mind is using the await keyword or using promises directly. This does not fully solve your problem though, because constructor can not be an async function.

I recommend this solution:

Move the call of fetchNews to an init method on the MyNews class and make it async.

class MyNews {
    ...
    async fetchNews() {
        await fetch(...);
    }
    ...
    async init() {
        await fetchNews();
    }
    ...
}
const news = new MyNews();
await news.init();
news.showNews();

You can find more on async constructors in this stackoverflow thread.

btw: the this.news; in the constructor seems unnecessary.

依 靠 2025-02-12 10:45:05

我建议将getandshownews()函数添加到您的课程中。

然后,我们将确保从fetchnews()提取呼叫中返回承诺,因此我们可以在另一个异步函数中等待等待。

getandShownews()函数中,我们将等待fetchnews()结果(承诺),这将确保填充新闻项目。
然后,我们将通过循环浏览每个项目来展示新闻。

您可以在班级以外的功能中执行此操作,但是在班上这样做似乎很有意义。

class MyNews {
  news = [];
  
  apiUrl = "https://jsonplaceholder.typicode.com/posts";
  
  constructor() {
    this.fetchNews();
  }
  
  fetchNews() {
    return fetch(this.apiUrl)
      .then(async (data) => {
        this.news = await data.json(); 
      })
      .catch((err) => {
        console.log(err)
      });        // ...
  }
  
  showNews(newsElementId, count = 8) {
    let newsElement = document.getElementById(newsElementId);
    for(let newsItem of this.news.slice(0,count)) {
      let el = document.createElement('li');
      el.innerText = newsItem.title;
      newsElement.appendChild(el);
    }
  }

  async getAndShowNews(newsElementId) {
    // Wait for the fetchNews() call to complete...
    await this.fetchNews();
    // Show the news...
    this.showNews(newsElementId);
  }
}
    
n = new MyNews();
n.getAndShowNews('news');
<b>News</b>
<ol id='news'>
</ol>

I'd suggest adding a getAndShowNews() function to your class.

We'll then ensure to return the promise from the fetchNews() fetch call, so we can await it in another async function.

In the getAndShowNews() function we'll await the fetchNews() result (a promise), this will ensure the news items are populated.
We'll then show the news by looping through each item.

You could do this in a function outside of the class, but it seems to make sense to do it in the class.

class MyNews {
  news = [];
  
  apiUrl = "https://jsonplaceholder.typicode.com/posts";
  
  constructor() {
    this.fetchNews();
  }
  
  fetchNews() {
    return fetch(this.apiUrl)
      .then(async (data) => {
        this.news = await data.json(); 
      })
      .catch((err) => {
        console.log(err)
      });        // ...
  }
  
  showNews(newsElementId, count = 8) {
    let newsElement = document.getElementById(newsElementId);
    for(let newsItem of this.news.slice(0,count)) {
      let el = document.createElement('li');
      el.innerText = newsItem.title;
      newsElement.appendChild(el);
    }
  }

  async getAndShowNews(newsElementId) {
    // Wait for the fetchNews() call to complete...
    await this.fetchNews();
    // Show the news...
    this.showNews(newsElementId);
  }
}
    
n = new MyNews();
n.getAndShowNews('news');
<b>News</b>
<ol id='news'>
</ol>

ペ泪落弦音 2025-02-12 10:45:05

构造函数的调用fetchnews不等待它。它只是为稍后将要解决的东西创造了诺言(例如,手柄)。您的显示的需要在fetchnews之后链接。另外,我会用async/等待为了清楚起见,

class MyNews {
  news = [];
  
  apiUrl = "https://jsonplaceholder.typicode.com/posts";
  
  constructor() {
    // this.news; - This statement does nothing
    // this.fetchNews(); - No need to call in constructor
  }
  
  fetchNews() {
    try {
      const data = await fetch(this.url)
      this.news = await data.json()
      console.log("A:",this.news.length); // i have results
    } catch (err) {
      console.log(err)
    }
  }
  
  showNews() {
    console.log("B:",this.news.length); // empty array
    
    return this.news;
  }
}
    

n = new MyNews();
n.fetchNews().then( () => n.showNews())
// OR
await n.fetchNews()
n.showNews()

我还将从fetchnews返回新闻,而不是保留为类成员

The constructor's call to fetchNews does NOT waits for it. It just creates a Promise (e.g a handle) to something that'll be resolved later. Your showNews needs to be chained after the fetchNews. Also, I would write it with async/await for clarity

class MyNews {
  news = [];
  
  apiUrl = "https://jsonplaceholder.typicode.com/posts";
  
  constructor() {
    // this.news; - This statement does nothing
    // this.fetchNews(); - No need to call in constructor
  }
  
  fetchNews() {
    try {
      const data = await fetch(this.url)
      this.news = await data.json()
      console.log("A:",this.news.length); // i have results
    } catch (err) {
      console.log(err)
    }
  }
  
  showNews() {
    console.log("B:",this.news.length); // empty array
    
    return this.news;
  }
}
    

n = new MyNews();
n.fetchNews().then( () => n.showNews())
// OR
await n.fetchNews()
n.showNews()

I would also return the news from fetchNews instead of keep as a class member

七秒鱼° 2025-02-12 10:45:05

对你来说还可以吗?

class MyNews {
  
  apiUrl = "https://jsonplaceholder.typicode.com/posts";
  
  constructor() {
    this.news=[];
  }
  
  async fetchNews() {
  const response= await  fetch(this.apiUrl);
  const data = await response.json();
  this.news= data;
  console.log("A:",this.news.length);
  return data;
  }
  
  async showNews() {
    await this.fetchNews();
    console.log("B:",this.news.length); // empty array
    return this.news;
  }
}
    
async function app(){
  n = new MyNews();
  const news= await n.showNews();
  console.log("C:", news.length);
}
app();
   

Is that OK for you ?

class MyNews {
  
  apiUrl = "https://jsonplaceholder.typicode.com/posts";
  
  constructor() {
    this.news=[];
  }
  
  async fetchNews() {
  const response= await  fetch(this.apiUrl);
  const data = await response.json();
  this.news= data;
  console.log("A:",this.news.length);
  return data;
  }
  
  async showNews() {
    await this.fetchNews();
    console.log("B:",this.news.length); // empty array
    return this.news;
  }
}
    
async function app(){
  n = new MyNews();
  const news= await n.showNews();
  console.log("C:", news.length);
}
app();
   

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文