【问题标题】:Asynchronous filtering an array of Promises异步过滤 Promise 数组
【发布时间】:2017-12-09 22:27:05
【问题描述】:

我有一个字符串数组 let symbols = ['abc', 'cde', 'edf', 'qqe', 'hrt'] 作为参数传递给函数:

async function fetchDetails(symbols) {
  let promises = symbols.map((s, i) => {
    return fetch(URL + s)
      .then(res => return res.json())
      .then(json => Object.assign({}, { [s]: json }))
  });
  console.log('promise:', promises)
  return Promise.all(promises);
}

我从 URL/'abc'、URL/'cde' 等获取数据并将其保存到 promises 数组中。

但是有 % 的可能性是我不会从服务器获得所有 5 个已解析的对象。然后在 console.log 中的 promises 数组如下所示:

我希望数组只包含 4 个已解决的项目(我传递给 Promise.all(),而不是 5 个(包括 4 个已解决和 1 个处于待处理状态)。

如果它是一个同步函数,我只需过滤数组即可。但我无权访问 [[PromiseStatus]] 属性,也不知道该怎么做。

由于我对 Javascript 还很陌生,因此我将不胜感激有关此 Async 事物的任何帮助。任何废料或代码,或建议在哪里搜索答案:)

编辑: 也许这会有所帮助,我发送查询的路线是这样构建的:

app.get('/data/:symbol', async (req, res) => {
  const { params: { symbol } } = req
  const data = await stocks.getData(symbol, new Date())
  res.send(data)
})

所以在出错的情况下,它不会发送任何错误,对吧? 这就是为什么我可能会有待处理状态而不是拒绝?

任务的解决方案

大家好,我用两件事解决了这个问题: 1. 感谢@Bergi,他指出 Pending Status 不是可以忽略的事实——我检查了服务器端,出现了第一个问题——没有处理错误。 2. 然后在修复服务器端之后,因为我可以将 Resolved Promises 与 Rejected 分开 - 我能够返回仅包含 Resolved Promise 的数组 - 使用这个自定义 Promise_all 解决方案:https://stackoverflow.com/a/46024590

所以我的最终代码看起来像这样:

async function fetchDetails(symbols) {
  let promises = symbols.map(async (s, i) => {
    return await fetch(URL + s)
      .then((res)=> {
        if (!res.ok) {
          throw new Error('Error with fetch')
        } else {
          return res.json();
        }
      })
      .then(json => Object.assign({}, { [s]: json })) 
      .catch(err => {
        return Promise.reject()})    
  });

  const Promise_all = promises => {
    return new Promise((resolve, reject) => {
      const results = [];
      let count = 0;
      promises.forEach((promise, idx) => {
        promise
          .catch(err => {
            return err;
          })
          .then(valueOrError => {
            results[idx] = valueOrError;
            count += 1;
            if (count === promises.length) resolve(results);
          });
      });
    });
  }; 

  const results = await Promise_all(promises)
  const validResults = results.filter(result => result !== undefined);

  return validResults;
}

非常感谢在这里写作的每一个人!

【问题讨论】:

  • 为什么承诺会一直挂起?你怎么知道什么时候停止等待?
  • 不确定它是否会回答您的问题,但服务器会模拟错误,并且有 5% 的机会它会返回错误而不是数据对象 - 在这种情况下,它处于待处理状态(我猜测)。当我遇到这种情况时,我想绕过这个承诺,只在数组中存储 4 个已解决的承诺。
  • 好吧,不,如果它返回错误状态,您应该拒绝您对 signal 错误的承诺,而不是让它等待处理。需要得到错误通知,否则我们无法区分服务器返回错误与服务器尚未返回任何内容。
  • 您希望在承诺失败之前超时多长时间?
  • 我用一些我认为有用的信息编辑了我的帖子。

标签: javascript asynchronous promise


【解决方案1】:

如果你想在某个超时后失败,你可以这样做:

const failIn = milliseconds =>
  setTimeout(
    _=>Promise.reject("timed out")
    ,milliseconds
  );

const Fail = function(details){this.details=details;};

const fetchDetails = symbols =>
  Promise.all(
    symbols.map((s, i) => {
      return Promise.race([
        fetch(URL + s),
        ,failIn(2000)//fail in 2 seconds
      ])
      .then(
        response=>[response,s],
        err = [new fail([err,URL+s]),s]
      )
    })
  )
  .then(
    responses =>
      responses.map(//map to json object from response or Fail type
        ([response,s]) => 
          (response && response.constructor === Fail)
            ? response
            : Object.assign({}, { [s]: response.json() })
      )
  );

Fail 对象仍然包含在结果中,如果您只是要忽略它们,可以使用过滤器将它们取出:

  .then(
    responses =>
      responses.filter(
        ([response,s]) => (response && response.constructor !== Fail)
      )
      .map(
        ([response,s]) => 
          Object.assign({}, { [s]: response.json() })
      )
  )

【讨论】:

  • 在该结果元组中包含一个布尔值可能比在 Fail 中包含一些值和其他不包含一些值更容易。
  • @Bergi 是的,如果你忽略了被拒绝的承诺,那么你可以做err =[false,s],注意到拒绝处理程序中有一个错误,因为它应该返回一个元组(修复)
猜你喜欢
  • 2020-06-16
  • 2022-09-23
  • 2021-02-15
  • 1970-01-01
  • 2018-12-10
  • 2020-09-11
  • 1970-01-01
  • 2019-06-26
  • 2014-05-04
相关资源
最近更新 更多