【问题标题】:Why are these nested promises not working?为什么这些嵌套的 Promise 不起作用?
【发布时间】:2017-09-06 15:25:51
【问题描述】:

我正在编写一个要在节点环境中的 cron 作业上运行的进程。

该进程从两个外部服务中获取两个用户列表,写入文件,并进行一些比较。

用户的来源之一是 Discourse 论坛,不幸的是,要获得完整的用户列表,我们必须获取多个 trust_level 列表并将它们连接起来。

我使用各种嵌套的 Promise 和 Promise.all 来构建它。但是,下面的函数调用它的then 回调太早了,在forumList.jsondatabaseList.json 甚至存在之前......我在这里做错了什么?

import superagent from 'superagent'
import { writeFileSync } from 'fs'

export default function fetchData() {

  const process = []

  const databaseFetch = new Promise((resolve, reject) => {

    superagent.get('https://our-api.com/api/1/databases/our-db/collections/users')
      .end((error, response) => {

        if (error) {
          reject(error)
        } else {
          writeFileSync('temp/databaseList.json', JSON.stringify(response.body))
          resolve()
        }

      })

  })

  const forumFetch = new Promise((resolve, reject) => {

    // For reference, see https://meta.discourse.org/t/how-do-i-get-a-list-of-all-users-from-the-api/24261/8
    // We have to do this because of the way the discourse API is built
    const discourseApiList = [
      'trust_level_0',
      'trust_level_1',
      'trust_level_2',
      'trust_level_3',
      'trust_level_4',
    ]

    let forumList = []

    const discoursePromises = discourseApiList.map((trustLevel) => {

      return new Promise((resolveInner, rejectInner) => {
        superagent.get(`https://our-website.com/forum/groups/${trustLevel}/members.json`)
          .end((error, response) => {

            if (error) {
              rejectInner(error)
              reject()
            } else {
              forumList = forumList.concat(response.body.members)
              resolveInner()
            }

          })
      })

    })

    Promise.all(discoursePromises).then(() => {
      writeFileSync('temp/forumList.json', JSON.stringify(forumList))
      resolve()
    })

  })

  process.push(databaseFetch)
  process.push(forumFetch)

  return Promise.all(process)

}

【问题讨论】:

  • 您是否错过了最后一行的返回?
  • @mikeapr4 不,没有区别
  • @JohnDoe - which .then 被调用的太早了?
  • @JaromandaX 然后then 来自fetchData() 本身,在单独的文件中被调用。我想读取fetchDatathen中的两个json文件,但是在它们存在之前就被调用了...
  • 想一想,如果您不返回最后的Promise.all,您将返回undefined ...并且没有.then 太早或以其他方式调用 - 我怀疑实际代码比你说的更多

标签: javascript arrays node.js ecmascript-6 es6-promise


【解决方案1】:

你不应该嵌套Promises,因为它们的唯一目的是创建线性代码。我建议这样做:

1- 创建discoursePromises 并使用Promise.all 解决它们

2- 然后,创建forumFetchdatabaseFetch 并使用Promise.all 解决它们

我认为您可能会发现有趣的async,这是一个很棒的流控制库。特别是看parallel。 希望这会有所帮助。

【讨论】:

  • 不,async.js 在基于 Promise 的代码中完全没有帮助。
  • 当然,您可以使用 Promise 或 async,因为它们是彼此的替代品。这意味着如果需要,必须重写代码以使用异步。
【解决方案2】:

Promise 代码在我看来很好,问题肯定出在其他地方。

function fetchData() {

  const process = []

  const databaseFetch = new Promise((resolve, reject) => {
    setTimeout(function() {
      console.log('resolving databaseFetch');
      resolve();
    }, Math.round(Math.random() * 10000));
  })

  const forumFetch = new Promise((resolve, reject) => {

    const discourseApiList = [
      'trust_level_0',
      'trust_level_1',
      'trust_level_2',
      'trust_level_3',
      'trust_level_4',
    ]

    let forumList = []

    const discoursePromises = discourseApiList.map((trustLevel) => {

      return new Promise((resolveInner, rejectInner) => {

        setTimeout(function() {
          console.log('resolving ' + trustLevel);
          resolveInner();
        }, Math.round(Math.random() * 10000));

      })

    })

    Promise.all(discoursePromises).then(() => {
      setTimeout(function() {
        console.log('resolving discoursePromises');
        resolve();
      }, Math.round(Math.random() * 1000));
    })

  })

  process.push(databaseFetch)
  process.push(forumFetch)

  return Promise.all(process)
}

fetchData().then(() => console.log('finished!'));

【讨论】:

    【解决方案3】:

    不要嵌套promise,如果你不想使用异步库,也不想promise.all,你可以写你的promise然后链接它们来控制它们的流程:

    识别承诺:

    const promise1Fun = () => {
     return new Promise((resolve, reject) => {
     //do stuff 
     })
    } 
    
    
    const promise2Fun = () => {
     return new Promise((resolve, reject) => {
     //do stuff 
     })
    } 
    

    链式承诺:

    promise1Fun.then(promise2Fun).catch((err) => console.error(err))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-12
      • 2021-03-01
      • 2016-01-31
      • 1970-01-01
      • 2022-01-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多