在本文中,我们将学习新的Fetch API的外观,解决的问题以及使用fetch()
函数在网页内检索远程数据的最实用方法。
多年来, XMLHttpRequest一直是Web开发人员值得信赖的伙伴。 无论是直接还是在幕后, XMLHttpRequest
都启用了Ajax和从Gmail到Facebook的全新的交互式体验。
但是, Fetch API逐渐取代了XMLHttpRequest
。 两者都可以用于发出网络请求,但是Fetch API是基于Promise的,它提供了一种更简洁,更简洁的语法,并使您远离回调地狱 。
Fetch API提供了在window
对象上定义的fetch()
方法,您可以使用该方法执行请求。 此方法返回一个Promise ,可用于检索请求的响应。
fetch
方法只有一个必填参数,它是您希望获取的资源的URL。 一个非常基本的示例如下所示。 这从r / javascript上Reddit上获取了前五篇文章:
fetch('https://www.reddit.com/r/javascript/top/.json?limit=5')
.then(res => console.log(res));
如果在浏览器的控制台中检查响应,则应该看到具有以下属性的Response
对象:
{
body: ReadableStream
bodyUsed: false
headers: Headers {}
ok: true
redirected: false
status: 200
statusText: ""
type: "cors"
url: "https://www.reddit.com/top/.json?count=5"
}
请求似乎成功了,但我们的前五名职位在哪里? 让我们找出答案。
在请求完成之前,我们不能阻止用户界面等待。 这就是为什么fetch()
返回Promise
的原因,该对象表示将来的结果。 在上面的示例中,我们使用then
方法来等待服务器的响应并将其记录到控制台。
现在,让我们看看一旦请求完成,我们如何从该响应中提取JSON有效负载:
fetch('https://www.reddit.com/r/javascript/top/.json?limit=5')
.then(res => res.json())
.then(json => console.log(json));
我们通过调用fetch()
启动请求。 兑现承诺后,它将返回一个Response
对象,该对象公开一个json
方法。 在第一个then()
我们可以调用此json
方法以将响应主体作为JSON返回。
但是, json
方法还返回一个promise,这意味着我们需要在JSON响应记录到控制台之前链接到另一个then()
。
为什么json()
返回诺言? 因为HTTP允许您逐块将内容流式传输到客户端,所以即使浏览器收到服务器的响应,内容主体也可能还不存在!
.then()
语法不错,但是在2018年处理承诺的一种更简洁的方法是使用async … await
-ES2017引入的新语法。 使用async Ú await
意味着我们可以将一个函数标记为async
,然后使用await
关键字await
诺言完成,然后作为常规对象访问结果。 所有现代浏览器(不是IE或Opera Mini)和Node.js 7.6+都支持异步功能。
这是上面使用async … await
示例的样子(略有扩展):
async function fetchTopFive(sub) {
const URL = `https://www.reddit.com/r/${sub}/top/.json?limit=5`;
const fetchResult = fetch(URL)
const response = await fetchResult;
const jsonData = await response.json();
console.log(jsonData);
}
fetchTopFive('javascript');
没有太大变化。 除了我们创建了一个async
函数(向其传递subreddit的名称)外,我们现在还在等待调用fetch()
的结果,然后再次使用await
从响应中检索JSON。
这是基本的工作流程,但是涉及远程服务的事情并不总是能顺利进行。
假设我们向服务器请求不存在的资源或需要授权的资源。 使用fetch()
,您必须在正常流中处理应用程序级错误,例如404响应。 如前所述, fetch()
返回带有ok
属性的Response
对象。 如果response.ok
为true
,则响应状态码位于200范围内:
async function fetchTopFive(sub) {
const URL = `http://httpstat.us/404`; // Will return a 404
const fetchResult = fetch(URL)
const response = await fetchResult;
if (response.ok) {
const jsonData = await response.json();
console.log(jsonData);
} else {
throw Error(response.statusText);
}
}
fetchTopFive('javascript');
来自服务器的响应代码的含义因API而异,并且通常仅检查response.ok
可能不够。 例如,即使您的API密钥无效,某些API也会返回200响应。 请务必阅读API文档!
要处理网络故障,请使用try … catch
块:
async function fetchTopFive(sub) {
const URL = `https://www.reddit.com/r/${sub}/top/.json?limit=5`;
try {
const fetchResult = fetch(URL)
const response = await fetchResult;
const jsonData = await response.json();
console.log(jsonData);
} catch(e){
throw Error(e);
}
}
fetchTopFive('javvascript'); // Notice the incorrect spelling
catch
块中的代码仅在发生网络错误时运行。
您已经了解了发出请求和阅读回复的基础知识。 现在,让我们进一步自定义请求。
查看上面的示例,您可能想知道为什么不能仅使用现有的XMLHttpRequest包装器之一 。 原因是fetch API提供的不仅仅是fetch()
方法。
虽然必须使用XMLHttpRequest
的相同实例来执行请求并检索响应,但fetch API允许您显式配置请求对象。
例如,如果您需要更改fetch()
发出请求的方式(例如,配置请求方法),则可以将Request
对象传递给fetch()
函数。 Request
构造函数的第一个参数是请求URL,第二个参数是配置请求的选项对象:
async function fetchTopFive(sub) {
const URL = `https://www.reddit.com/r/${sub}/top/.json?limit=5`;
try {
const fetchResult = fetch(
new Request(URL, { method: 'GET', cache: 'reload' })
);
const response = await fetchResult;
const jsonData = await response.json();
console.log(jsonData);
} catch(e){
throw Error(e);
}
}
fetchTopFive('javascript');
在这里,我们指定了request方法,并要求它不要缓存响应。
您可以通过将Headers
对象分配给请求headers
字段来更改请求标headers
。 以下是仅使用'Accept'
标头要求JSON内容的方法:
const headers = new Headers();
headers.append('Accept', 'application/json');
const request = new Request(URL, { method: 'GET', cache: 'reload', headers: headers });
您可以从旧请求中创建一个新请求,以针对不同的用例进行调整。 例如,您可以创建从GET请求到同一资源的POST请求。 这是一个例子:
const postReq = new Request(request, { method: 'POST' });
您还可以访问响应头,但请记住,它们是只读值。
fetch(request).then(response => console.log(response.headers));
Request
和Response
严格遵循HTTP规范; 如果您曾经使用服务器端语言,则应该识别它们。 如果您想了解更多信息,可以在MDN的Fetch API页面上阅读有关它们的全部信息。
为了使本文更完整,这是一个可运行的示例,该示例演示如何从特定的subreddit中获取前五个帖子,并在列表中显示其详细信息。
请参阅CodePen上的SitePoint ( @SitePoint )提供的Pen Fetch API演示 。
尝试输入一些子索引(例如“ javascript”,“ node”,“ linux”,“ lolcats”)以及一些不存在的子索引。
在本文中,您已经看到了新的Fetch API的外观以及解决的问题。 我已经演示了如何使用fetch()
方法检索远程数据,如何处理错误以及如何创建Request
对象来控制request方法和标头。
如下图所示,对fetch()
支持很好。 如果您需要支持较旧的浏览器,可以使用polyfill 。
因此,下次您到达像jQuery这样的库来发出Ajax请求时,请花点时间考虑是否可以使用本机浏览器方法。
From: https://www.sitepoint.com/introduction-to-the-fetch-api/