【问题标题】:How to avoid using setTimeout to wait for Promises to resolve?如何避免使用 setTimeout 等待 Promises 解决?
【发布时间】:2018-04-01 05:19:04
【问题描述】:

我有一个 subreddit,我想在其中解析所有日常线程的 cmets。为此,我必须获取线程 ID。我使用 snoowrap 作为 api 包装器。

我很难理解节点的异步特性。当我打电话给subreddit.search({query: 'Daily General Discussion - ' + date}) 时,我得到了一个 Promise。

然后我解决了获取线程 ID 并将其推送到新数组的承诺(我尝试使用 arr[i] = a[0].id 保存值,但只有最后一个结果存储在我的数组中,这表明 Promise.resolve 被调用在我的 for 循环之后)。

如何在 Promise 解决之前停止执行其余代码?使用 setTimeout 似乎效率低下且不可靠,因为解决时间可能比我的 setTimeout 时间长。

下面的代码有效,我只是想避免使用 setTimeout。

const subreddit = reddit.getSubreddit('subreddit')

let numberOfDaysBack = 50;
let arrIds           = new Array(0);

for (var i = 0; i < numberOfDaysBack; i++) {
  let date        = moment().subtract(0+i, 'days').format('MMMM D, YYYY')
  let dailyThread = subreddit.search({query: 'Daily General Discussion - ' + date})

  Promise.resolve(dailyThread).then(a=>{
    arrIds.push(a[0].id)
  })
}

setTimeout(function(){
  console.log(arrIds)
},1000)

doOtherStuff(arrIds)

【问题讨论】:

  • @PatrickEvans 你能用我的例子明确地告诉我吗?我目前正在使用Promise.resolve().then()
  • The code below works, I just want to avoid using setTimeout. - 等待承诺解决
  • @JaromandaX 但是,如果我想使用数组中的值进行更多计算,如何确保在执行更多代码之前解决承诺?
  • 您等待使用 Promise.all(promises).then(results =&gt; { here the results are yours to play with }) 解决的承诺

标签: javascript node.js promise


【解决方案1】:

将 Promise 映射到一个数组中,然后使用 Promise.all() 来同时运行它们。解决所有承诺后,您将在then 中获得结果。

const subreddit = reddit.getSubreddit('subreddit')

let numberOfDaysBack = 50
let arrIds

let promises = Array(numberOfDaysBack)
  .fill()
  .map((_, i) => {
    let date        = moment().subtract(0+i, 'days').format('MMMM D, YYYY')
    let dailyThread = subreddit.search({query: 'Daily General Discussion - ' + date})
    return dailyThread
  })

Promise
  .all(promises)
  .then(results => {
    arrIds = results.map(result => result.id)
    doOtherStuff(arrIds)
  });

【讨论】:

  • 承诺没有“运行”。
  • @shawon191 我认为我无法访问 then() 回调范围之外的 arrIds。
  • @Huy 不,你不能。这不是 promise 的设计方式。您只需在then 中输入doOtherStuff(arrIds)。 (答案已更新)
  • @shawon191 Promise 只是结果值。他们不任何事情。它们可以被观察,它们可以被等待。一些异步操作并发运行是因为它们是同时启动的——独立地,而不是顺序地——并且它们返回承诺或在Promise.all 中使用的承诺根本不重要。
  • @Bergi 我的意思是结合映射数组的动作,然后使用Promise.all 来实现并发。虽然Promise.all 在并发中并不重要,但在这种情况下有必要以正确的顺序接收接收到的值。非并发选项是通过添加到then 来按顺序将新任务添加到循环中。虽然我理解您所说的 Promise 不是“运行”的意思,但我觉得使用该术语很方便,因为它是管理正在运行的异步任务的方法。
【解决方案2】:

将你所有的 Promise 存储在一个数组中,然后使用 Promise.all:

const subreddit = reddit.getSubreddit('subreddit')

let numberOfDaysBack = 50;
let idPromises       = [];

for (var i = 0; i < numberOfDaysBack; i++) {
  let date        = moment().subtract(i, 'days').format('MMMM D, YYYY')
  let dailyThread = subreddit.search({query: 'Daily General Discussion - ' + date})
  idPromises.push(dailyThread.then(a => a[0].id));
}

Promise.all(idPromises).then(arrIds => {
  console.log(arrIds)
});

【讨论】:

    【解决方案3】:

    您可以在这种类型的用例中使用 Promise.all(),您必须创建一个 Promise 列表并等待它们全部完成。

    const subreddit = reddit.getSubreddit('subreddit');
    
    const numberOfDaysBack = 50;
    const arrIds = new Array(0);
    const promises = [];
    
    for (var i = 0; i < numberOfDaysBack; i++) {
      const date = moment().subtract(0+i, 'days').format('MMMM D, YYYY');
      const dailyThread = subreddit.search({query: 'Daily General Discussion - ' + date});
    
      promises.push(dailyThread);
    }
    
    Promise.all(promises).then(function(results){
      results.forEach(function(a){
        arrayIds.push(a[0].id);
      });
    
      console.log(arrayIds);
    });
    

    【讨论】:

      【解决方案4】:

      假设 subreddit.search 返回一个 Promise

      const subreddit = reddit.getSubreddit('subreddit')
      
      let numberOfDaysBack = 50;
      
      Promise.all(Array.fill(numberOfDaysBack).map((unused, i) => {
          let date        = moment().subtract(0+i, 'days').format('MMMM D, YYYY')
          return subreddit.search({query: 'Daily General Discussion - ' + date}).then(a => a[0].id);
      })).then(results => {
          // here results is the array of "a[0].id"
      });
      // out here, don't expect to access results without using kludges
      // so do it all in the `.then`
      

      【讨论】:

      • 我明白了。感谢您的解释,我希望能够访问 then() 块之外的结果,但看起来不可能。
      猜你喜欢
      • 2021-05-19
      • 2019-01-12
      • 2022-01-21
      • 1970-01-01
      • 2023-03-19
      • 1970-01-01
      • 1970-01-01
      • 2021-06-21
      • 2014-12-04
      相关资源
      最近更新 更多