将 Fetch API 与 Promise.all 一起使用

Posted

技术标签:

【中文标题】将 Fetch API 与 Promise.all 一起使用【英文标题】:Using Fetch API with Promise.all 【发布时间】:2017-11-25 09:04:16 【问题描述】:

我的目标是从两个 URL 获取数据并仅在两个 URL 都成功返回时执行操作。另一方面,如果其中任何一个失败,我想返回一个错误。我已经玩弄了我的代码并设法获得了预期的效果。

我的问题是,是否有更有效、更简洁的方法来实现相同的功能?

辅助函数

let status = (r) =>   
  if (r.ok)   
    return Promise.resolve(r)  
   else   
    return Promise.reject(new Error(r.statusText))  
    


let json = (r) => r.json();

请求

let urls = [
    'http://localhost:3000/incomplete',
    'http://localhost:3000/complete'
]

let promises = urls.map(url => 

    return fetch(url)  
    .then(status)  
    .then(json)  
    .then(d => Promise.resolve(d))
    .catch(e => Promise.reject(new Error(e)));

);

Promise.all(promises).then(d => 
    // do stuff with d
).catch(e => 
    console.log('Whoops something went wrong!', e);
);

【问题讨论】:

如果您的代码有效,那么codereview.stackexchange.com 可能是一个更好的提问地点。乍一看,.then(d => Promise.resolve(d)).catch(e => Promise.reject(new Error(e))); 行似乎没有必要(它们不会做任何不会发生的事情)。 status 函数也可以是 if (r.ok) return r; else throw new Error(r.statusText); 。无需在不需要的地方创建承诺。 在你的地图函数内部不要调用“then”,喜欢的只是返回 fetch(url) @FelixKling 谢谢!我不知道该网站存在!太棒了,我把那条线减少到let promises = urls.map(url => fetch(url).then(status).then(json)); @PaulOkeke 如果我只是在map 中返回fetch(url),那么我如何检查我的回复是否正常? @Samuel 您将检查 Promises.all 中的所有响应。例如 Promises.all (promises).then(allfetch => allfetch [0], allfetch [1].... ) 。 Promise.all 将自动调用所有 Promise 上的“then”函数,并且所有 Promise 的结果都以数组的形式返回,按照它们添加的顺序。我目前正在用手机打字……您可以查看文档。 developer.mozilla.org/en/docs/Web/javascript/Reference/… 【参考方案1】:

使用 fetchOk 获得更好的错误消息,使用 destructuring 访问结果:

let fetchOk = (...args) => fetch(...args)
  .then(res => res.ok ? res : res.json().then(data => 
    throw Object.assign(new Error(data.error_message), name: res.statusText);
  ));

Promise.all([
  'http://localhost:3000/incomplete',
  'http://localhost:3000/complete'
].map(url => fetchOk(url).then(r => r.json()))).then(([d1, d2]) => 
  // do stuff with d1 and d2
).catch(e => console.error(e));


// Work around ***'s broken error logger.
var console =  error: msg => div.innerhtml += msg + "<br>" ;
&lt;div id="div" style="white-space: pre;"&gt;&lt;/div&gt;

【讨论】:

我看不出这比 OP 已经拥有的“更有效或更简洁的方式”。此外,OP 不想在错误情况下调用 .json() @Bergi 错误消息是 JSON 格式。你不想知道出了什么问题吗? - 我认为大多数人更喜欢一个 fetch 函数,它会抛出 not-ok,并抛出一个信息错误。否则我们最终不得不记住在每次提取时检查状态,这很容易出错。这是一种更好的重用模式,更简洁。 你怎么知道错误信息是 JSON 格式的?据我们所知,OP 要求提供与他已经拥有的功能相同的代码。 @Bergi OP 期望 json 成功,并希望 !r.ok 抛出错误,所以我假设任何错误消息也会在 json 中。这不常见吗? OP 的示例实际上并没有演示此失败路径,但是当我 Run code snippet 在我的 other answer 中时,这似乎有效。【参考方案2】:

// https://jsonplaceholder.typicode.com - Provides test JSON data
var urls = [
  'https://jsonplaceholder.typicode.com/todos/1',
  'https://jsonplaceholder.typicode.com/todos/2',
  'https://jsonplaceholder.typicode.com/posts/1',
  'https://jsonplaceholder.typicode.com/posts/2'
];

// Maps each URL into a fetch() Promise
var requests = urls.map(function(url)
  return fetch(url)
  .then(function(response) 
// throw "uh oh!";  - test a failure
return response.json();
  )  
);

// Resolve all the promises
Promise.all(requests)
.then((results) => 
  console.log(JSON.stringify(results, null, 2));
).catch(function(err) 
  console.log("returns just the 1st failure ...");
  console.log(err);
)
&lt;script src="https://getfirebug.com/firebug-lite-debug.js"&gt;&lt;/script&gt;

【讨论】:

【参考方案3】:
const urls = [
    'http://localhost:3000/incomplete',
    'http://localhost:3000/complete'
]
const json = (r) => r.json()
const status = (r) => r.ok ? Promise.resolve(r) : Promise.reject(new Error(r.statusText))
const toRequest = url => fetch(url).then(status).then(json)
const onError = e =>  console.log('Whoops something went wrong!', e) 
const consumeData = data =>  console.log('data: ', data) 

Promise.all(urls.map(toRequest))
  .then(consumeData)
  .catch(onError)

【讨论】:

以上是关于将 Fetch API 与 Promise.all 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

使用 Promise.all() 从 Axios 转换为 Fetch

将Promise.all与easyPost API一起用于多个跟踪状态请求

将 Promise.all 与 easyPost API 一起用于跟踪状态的多个请求

如何将 Promise.all() 限制为每秒 5 个 Promise?

如何使用 Promise.all 方法? [关闭]

谈谈 Promise 以及实现 Fetch 的思路