【问题标题】:How to return response/promises in forEach that stores into array?如何在存储到数组中的 forEach 中返回响应/承诺?
【发布时间】:2020-04-03 01:47:39
【问题描述】:

我已经阅读了一堆类似类型的问题,但无法让它在我自己的用例中发挥作用。我正在抓取 Twitter 并使用 Twitter 模块。

const Twitter = require("twitter");

var i = 0;
var store = [];

var clients = [
    new Twitter({
        consumer_key: "",
        consumer_secret: "",
        access_token_key: "",
        access_token_secret: "",
    }),
    new Twitter({
        consumer_key: "",
        consumer_secret: "",
        access_token_key: "",
        access_token_secret: "",
    }),
]

const users = [
    'twitteruser1',
    'twitteruser2',
]

users.forEach(function (user) {
    clients[0].get("statuses/user_timeline", { screen_name: user, count: 5 }, (error, tweets, response) => {
        try {
            tweets.forEach(function(tweet){
                store.push(tweet.id_str)
            }
        } catch (error) {
            console.log(error)
        }
    })
})

我需要它在我的其余代码之前运行,当然如果没有适当的承诺解决它就不会。但是,尽管查看了我阅读过的所有解决所有承诺的内容,但我无法使其正常工作。

这是显示如何使用数组的下一个 sn-p 代码:

clients.forEach(function (client) {
    setTimeout(() => {
        setInterval(() => {
            client.get("statuses/user_timeline", { screen_name: users[i % users.length], count: 1}, (error, tweets, response) => {
                try {
                    if (!store.some(found => found == tweets[0].id_str)) {
                        ... etc ...

基本上存储每个用户的最后 5 条推文,然后检查他们是否发送了一个在数组“存储”(新推文)中尚不存在的推文,然后对其进行操作。

谢谢!

【问题讨论】:

  • 您应该能够将一些事情移动到异步函数中,然后在继续之前使用Promise.all 解决这些事情。从未使用过 twitter 包,所以我不确定具体的解决方案
  • setTimeout(() => { setInterval(() => { ... 这在我看来是一个真的坏主意。
  • 我必须错开 20 组不同的 twitter api 密钥。由于速率限制,这就是我所做的:}, 1000)}, (1000 / clients.length) * (clients.indexOf(client) % clients.length)) 有更可靠的方法吗?我必须在 50 毫秒内错开 20 个请求

标签: javascript arrays asynchronous foreach promise


【解决方案1】:

Promise.all 是并行执行多个异步任务的最佳选择,每个任务的结果都以数组形式返回:

const Twitter = require("twitter");

function getLatestUserTweets() { 
  // This will be an array of arrays
  return Promise.all(users.map(user => new Promise((resolve, reject) => {
    clients[0].get(
      "statuses/user_timeline", { screen_name: user, count: 5 },
      (error, tweets, response) => error ? reject(error) : resolve(tweets)
    );
  })));
}

或者希望 Twitter API 可以选择直接使用 Promises,这样您就可以进一步简化,而无需包装在 new Promise 中。

【讨论】:

    【解决方案2】:

    您显然已经看到,在 forEach 循环中使用异步操作并不能很好地发挥作用。为此,我可以从this lovely article 建议以下代码。如果你快速阅读这篇文章,你可能会更好地理解它的工作原理。

    async function asyncForEach(array, callback) {
      for (let index = 0; index < array.length; index++) {
        await callback(array[index], index, array);
      }
    }
    

    然后您可以按如下方式调用此函数:

    const start = async () => {
      await asyncForEach([1, 2, 3], async (num) => {
        await waitFor(50);
        console.log(num);
      });
      console.log('Done');
    }
    
    start();
    
    // Result
    // 1
    // 2
    // 3
    // Done
    

    另一个可能的解决方案是 Jhecht 建议的; Promise.all() 的用法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-17
      • 1970-01-01
      • 2016-11-28
      • 2020-04-02
      • 1970-01-01
      • 2019-09-05
      • 2019-09-08
      • 2022-09-23
      相关资源
      最近更新 更多