将 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>" ;
<div id="div" style="white-space: pre;"></div>
【讨论】:
我看不出这比 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);
)
<script src="https://getfirebug.com/firebug-lite-debug.js"></script>
【讨论】:
【参考方案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 一起用于跟踪状态的多个请求