在 javascript 中的另一个 fetch 中使用 fetch
Posted
技术标签:
【中文标题】在 javascript 中的另一个 fetch 中使用 fetch【英文标题】:using a fetch inside another fetch in javascript 【发布时间】:2017-04-20 05:55:12 【问题描述】:我想获得一个 api,然后再调用另一个。在 javascript 中使用这样的代码是否明智?
fetch(url,
method: 'get',
).then(function(response)
response.json().then(function(data)
fetch(anotherUrl).then(function(response)
return response.json();
).catch(function()
console.log("Booo");
);
);
)
.catch(function(error)
console.log('Request failed', error)
);
【问题讨论】:
你想达到什么目的?第二次调用是否依赖于第一次调用的响应数据? @guest271314 是的,第二次调用取决于第一次调用的响应数据。 您也可以使用.then()
链接调用
如果你在每个 promise (then
) 回调中都没有 return
,那么你最终的 .catch()
将无法工作。
【参考方案1】:
Fetch 返回一个promise,你可以chain multiple promises,在第二个请求中使用第一个请求的结果,以此类推。
本示例使用SpaceX API 获取最新发射的信息,查找火箭的 id,并获取火箭的信息。
const url = 'https://api.spacexdata.com/v4';
const result = fetch(`$url/launches/latest`, method: 'get' )
.then(response => response.json()) // pass the data as promise to next then block
.then(data =>
const rocketId = data.rocket;
console.log(rocketId, '\n');
return fetch(`$url/rockets/$rocketId`); // make a 2nd request and return a promise
)
.then(response => response.json())
.catch(err =>
console.error('Request failed', err)
)
// I'm using the result const to show that you can continue to extend the chain from the returned promise
result.then(r =>
console.log(r.first_stage); // 2nd request result first_stage property
);
.as-console-wrapper max-height: 100% !important; top: 0;
【讨论】:
谢谢@Henke。已更新至 spacex api 的 v4。 我更喜欢较小的 JSON 输出,但不幸的是我没有更好的 URL 使用建议。 @Henke - 好主意。我已将其更改为仅显示 1st stage 属性。 如果我需要来自第一个fetch
的更多属性怎么办?它在链式提取中仍然可用吗?为什么return fetch
有一个then
而不是2 个thens
?第二次提取中的data
对象在哪里?我的用例:使用来自 github api 的一些数据获取我的所有 repos,并使用另一个 api - return fetch
- 从 iso 转换为德国日期格式。因此,我需要通过 repos 及其属性(如日期和名称)循环返回获取。
@Timo - 您可以链接多个 catch 然后阻止 - 请参阅此 article。您的 then(response => return response.json())
是语法错误。箭头函数自动返回。你可能有大括号,这就是你需要返回的原因。【参考方案2】:
嵌套fetch()
调用没有问题。这取决于您试图通过嵌套调用来实现什么。
您也可以使用.then()
链接调用。另见How to structure nested Promises
fetch(url)
.then(function(response)
return response.json()
)
.then(function(data)
// do stuff with `data`, call second `fetch`
return fetch(data.anotherUrl)
)
.then(function(response)
return response.json();
)
.then(function(data)
// do stuff with `data`
)
.catch(function(error)
console.log('Requestfailed', error)
);
【讨论】:
【参考方案3】:这是人们在开始使用 Promises 时经常遇到的一个问题,包括我自己在内。但是,首先...
很高兴您尝试使用新的Fetch API,但如果我是您,我现在会使用 XMLHttpRequest 实现,例如 jQuery AJAX 或 Backbone 覆盖的 jQuery .ajax()
实现,如果您已经在使用这些库。原因是 Fetch API 仍然很新,因此在这个阶段是实验性的。
话虽如此,人们肯定会使用它,但我不会在自己的生产代码中使用它,直到它脱离“实验”状态。
如果您决定继续使用fetch
,则可以使用polyfill。 注意:您必须跳过额外的障碍才能使错误处理正常工作,并从服务器接收 cookie。如果您已经在加载 jQuery 或使用 Backbone,那么现在就坚持下去;无论如何,并不完全可怕。
现在进入代码:
你想要一个 flat 结构,否则你就错过了 Promise 的意义。嵌套 Promise 是不明智的,因为 Promises 解决了嵌套异步回调(回调地狱)无法解决的问题。
只需使用更易读的代码结构,您就可以节省时间和精力,并减少错误代码。这不是一切,但可以说是游戏的一部分。
Promises 是关于让异步代码保留大部分丢失的属性 同步代码,例如扁平缩进和一个异常 频道。
-- Petka Antonov (Bluebird Promise Library)
// run async #1
asyncGetFn()
// first 'then' - execute more async code as an arg, or just accept results
// and do some other ops
.then(response =>
// ...operate on response data...or pass data onto next promise, if needed
)
// run async #2
.then(asyncGetAnotherFn)
.then(response =>
// ...operate on response data...or pass data onto next promise, if needed
)
// flat promise chain, followed by 'catch'
// this is sexy error handling for every 'then' above
.catch(err =>
console.error('Request failed', err)
// ...raise exeption...
// ... or, retry promise...
)
【讨论】:
数据如何从一个承诺链发送到下一个承诺链将对读者有所帮助。否则很棒的帖子。 我部分同意@Si8,但在fetch
处看不到有关该问题的任何有价值的信息。【参考方案4】:
在 javascript 中使用这样的代码是否明智?
是的。您的代码很好。
除了第二次请求之后,
fetch(anotherUrl).then(function(response)
,
我会替换return response.json();
与response.json().then(function(data2)
- 就像在
第一个请求。
然后变量data2
将包含内部的响应主体
URL 请求,根据需要。
这意味着 – 无论您想对 data2
做什么,您都必须这样做
在第二个回调中(因为您没有返回承诺。)
此外,再打印几份将有助于了解正在发生的事情。
1。原始代码——稍作修改
进行这些更改后,这是一个堆栈片段,其中包含您的 代码: 1
const url = 'https://jsonplaceholder.typicode.com/todos/1';
const anotherUrl = 'https://jsonplaceholder.typicode.com/todos/4';
fetch(url,
method: 'get'
).then(function (response)
response.json().then(function (data)
console.log('Response body of outer "url":');
console.log(JSON.stringify(data) + '\n\n');
fetch(anotherUrl).then(function (response)
response.json().then(function (data2)
console.log('Response body of inner "anotherUrl":');
console.log(JSON.stringify(data2) + '\n\n');
);
).catch(function ()
console.log('Booo');
);
);
)
.catch(function (error)
console.log('Request failed', error);
);
.as-console-wrapper max-height: 100% !important; top: 0;
真的很好,虽然胖箭头风格更常见 这些天来定义一个函数。
2。代码重构
这是您的代码的重构版本。
它有一个内部 chained/nested 请求 – fetch(urlInner)
–
取决于从先前/外部请求中检索到的数据:fetch (urlOuter)
。
通过返回外部和内部 URL 获取的承诺,
稍后可以在代码中访问/解决承诺的结果:
2
const urlOuter = 'https://jsonplaceholder.typicode.com/todos/1';
let urlInner = '';
const resultPromise = fetch(urlOuter)
.then(responseO => responseO.json())
.then(responseBodyO =>
console.log('The response body of the outer request:');
console.log(JSON.stringify(responseBodyO) + '\n\n');
const neededValue = responseBodyO.id + 3;
urlInner = 'https://jsonplaceholder.typicode.com/todos/' + neededValue;
console.log('neededValue=' + neededValue + ', URL=' + urlInner);
return fetch(urlInner)
.then(responseI => responseI.json())
.then(responseBodyI =>
console.log('The response body of the inner/nested request:');
console.log(JSON.stringify(responseBodyI) + '\n\n');
return responseBodyI;
).catch(err =>
console.error('Failed to fetch - ' + urlInner);
console.error(err);
);
).catch(err =>
console.error('Failed to fetch - ' + urlOuter);
console.error(err);
);
resultPromise.then(jsonResult =>
console.log('Result - the title is "' + jsonResult.title + '".');
);
.as-console-wrapper max-height: 100% !important; top: 0;
请注意,缩进的深度不能超过 8 个空格。
3。这种代码风格的优点
这显然是一种嵌套的代码编写方式——意味着
链式请求fetch(urlInner)
缩进并在
第一个请求的回调fetch(urlOuter)
。
然而,缩进树是合理的,这种风格很能引起共鸣
根据我对链接请求的直觉。 – 但更重要的是,
这种风格使得编写精确定位的错误消息成为可能
哪个 URL 失败。
运行下面的 sn -p 以查看错误消息如何表明它是 导致错误的内部/第二个 URL:
const urlOuter = 'https://jsonplaceholder.typicode.com/todos/1';
let urlInner = '';
const resultPromise = fetch(urlOuter)
.then(responseO => responseO.json())
.then(responseBodyO =>
console.log('The response body of the outer request:');
console.log(JSON.stringify(responseBodyO) + '\n\n');
const neededValue = responseBodyO.id + 3;
urlInner = 'https://VERY-BAD-URL.typicode.com/todos/' + neededValue;
console.log('neededValue=' + neededValue + ', URL=' + urlInner);
return fetch(urlInner)
.then(responseI => responseI.json())
.then(responseBodyI =>
console.log('The response body of the inner/nested request:');
console.log(JSON.stringify(responseBodyI) + '\n\n');
return responseBodyI;
).catch(err =>
console.error('Failed to fetch - ' + urlInner);
console.error(err);
);
).catch(err =>
console.error('Failed to fetch - ' + urlOuter);
console.error(err);
);
resultPromise.then(jsonResult =>
console.log('Result - the title is "' + jsonResult.title + '".');
);
.as-console-wrapper max-height: 100% !important; top: 0;
4。展平所有出现的.then()
?
在他人的启发下,您可能会倾向于将所有出现的
.then()
,如下图。
我会建议反对这样做——或者至少三思而后行 正在做。为什么?
在没有错误的情况下,没关系。 如果有有个错误,这样的样式会导致不太明显的错误 消息:const urlOuter = 'https://jsonplaceholder.typicode.com/todos/1';
let urlInner = '';
const resultPromise = fetch(urlOuter)
.then(responseO => responseO.json())
.then(responseBodyO =>
console.log('The response body of the outer request:');
console.log(JSON.stringify(responseBodyO) + '\n\n');
const neededValue = responseBodyO.id + 3;
urlInner = 'https://VERY-BAD-URL.typicode.com/todos/' + neededValue;
console.log('neededValue=' + neededValue + ', URL=' + urlInner);
return fetch(urlInner);
)
.then(responseI => responseI.json())
.then(responseBodyI =>
console.log('The response body of the inner/nested request:');
console.log(JSON.stringify(responseBodyI) + '\n\n');
return responseBodyI;
).catch(err =>
console.error('Failed to fetch one or more of these URLs:');
console.log(urlOuter);
console.log(urlInner);
console.log(err);
);
.as-console-wrapper max-height: 100% !important; top: 0;
代码很平坦,但最后捕获的错误无法决定 哪些 URL 请求失败。
1 此答案的所有 sn-ps 均符合
JavaScript Semistandard Style.2 关于第 11 行 – return fetch(urlInner)
– 它是
非常很容易忘记return
获取。
(我曾经忘记它,甚至在写完这个答案之后。)
如果您确实忘记它,resultPromise
将不会包含任何承诺
全部。
然后 sn-p 中的最后三行将失败——它们将输出
什么都没有。
结果完全失败!
【讨论】:
【参考方案5】:我没有看到带有 async/await 语法糖的答案,所以我发布了我的答案。
在 javascript 中获取“内部”另一个获取的另一种方法是 -
try
const response = await fetch(url, method: 'get');
const data = response.json();
//use the data...
const anotherResponse = await fetch(url, method: 'get');
const anotherdata = anotherResponse.json();
//use the anotherdata...
catch (error)
console.log('Request failed', error) ;
所以实际上你是一个接一个地调用 url。
此代码将在异步上下文中运行。
【讨论】:
【参考方案6】:我建议使用axios,这样会更好,而且您不必处理 JSON 格式。此外,代码看起来更简洁,更易于理解。
axios.get(firstUrl).then((resp1) =>
// Handle success of first api
axios.get(secondUrl).then((resp2) =>
return resp2.data
).catch((error) => /* Handle error of second api */ );
).catch((error) => /* Handle error of first api */ );
来自 LogRocket.com 的块引用:
与 Fetch 一样,Axios 也是基于 Promise 的。但是,它提供了更多 强大而灵活的功能集。
使用 Axios 优于原生 Fetch API 的优势包括:
请求和响应拦截 简化的错误处理 XSRF 防护 支持上传进度 响应超时 取消请求的能力 支持旧版浏览器 自动 JSON 数据转换
【讨论】:
【参考方案7】:我会使用 fetches 数组或 url 数组,两者都按照您希望执行它们的顺序。然后使用reduce依次执行。这样它的可扩展性就更高了。
const urls = [
'https://api.spacexdata.com/v4/launches/latest',
'https://api.spacexdata.com/v4/launches/latest',
'https://api.spacexdata.com/v4/launches/latest'
];
// handle the fetch logic
// and handle errors
const handleFetch = async (url) =>
const resp = await fetch(url).catch(console.error);
return resp.json()
// reduce fetches, receives the response
// of the previous, log it (and maybe use it as input)
const reduceFetch = async (acc, curr) =>
const prev = await acc;
console.log('previous call:', prev);
return handleFetch(curr);
const pipeFetch = async urls => urls.reduce(reduceFetch, Promise.resolve(''));
pipeFetch(urls).then(console.log);
【讨论】:
以上是关于在 javascript 中的另一个 fetch 中使用 fetch的主要内容,如果未能解决你的问题,请参考以下文章
需要帮助将 c-strings 从嵌入式 SQL fetch 复制到单独结构中的另一个 c-string
JavaScript 中的 Promises/Fetch:如何从文本文件中提取文本
Javascript - 从浏览器中的另一个模块设置“让”变量
javascript 在Express.JS中的Node.JS中使用Fetch API