JavaScript fetch 快速入门
fetch API 简介
ECMAScript 2015(ES6) 标准的发布已经三年有余,现代浏览器对ES6语法的支持趋于完善,用Promise对象处理异步请求被越来越多的开发者应用。为了更好地处理异步请求,作为对现有的XMLHttpRequest方法的替代,JavaScript引入了fetch方法,基于Promise处理异步请求。
更多关于fetch的介绍,可以参考MDN关于fetch的介绍。
这篇文章假设你具备:
有JavaScript基础
对Promise对象有了解
如果你想了解Promise的相关知识,可以参考阮一峰老师的书籍
fetch 的浏览器支持情况
参考Can I Use,下图为本文写作时间 的支持情况,点击这里查看最新的支持情况
可以看到目前全球范围内支持已经达到87.84%,在中国也有69.65%的支持,并且将来这个数据必然会继续升高,已经广泛地被主流浏览器所支持(IE除外)。
使用fetch
fetch接受两个参数,url和init,其中url参数是必须的,而init参数是可选的。
url参数是一个字符串,表示请求的url地址,而init是一个对象,在里面可以对这个请求进行配置,例如设置请求方法,设置请求头等,如果不传入init参数,将会采用默认的配置,可以点击这里查看MDN文档对fetch第二个参数的说明以及默认配置。
返回一个包含Promise对象,在这个对象的resolve方法中可以访问到请求的结果,是一个Response对象,可以点击这里查看MDN文档对Response对象的属性和方法的具体说明。
你无须对fetch的配置以及Response十分熟悉,也可以方便地使用fetch,使用默认的配置即可完成很多工作,当你有特定需求时再回过头来了解细节即可,接下来我们来写一个最简单的fetch。
一个最简单的fetch
让我们来写一个最简单的fetch,从服务器上获取一个json文件并打印出来,你可以点击这里查看它。
这个JSON文件是这样的:
[
{
"name": "张三",
"age": 18
},
{
"name": "李四",
"age": 20
},
{
"name": "王五",
"age": 22
}
]
现在我们用fetch获取这个文件,并把它打印出来,要知道,fetch默认使用的是GET方法,所以在这里我们不需要第二个参数就可以达到我们的目的。
fetch('https://raw.githubusercontent.com/DaKoala/fetch-example/master/people.json')
.then(res => res.json())
.then(json => console.log(json))
// [{ name: "张三", age: 18 }, { name: "李四", age: 20 }, { name: "王五", age: 22 }]
请注意,这里我们调用了then方法2次,在第一个then中,我们得到了一个Response对象,我们调用它的.json()方法,来获取服务器响应中的数据,需要注意的是,res.json()返回的是一个Promise对象,而不是JSON化的数据,参考MDN文档中的说明:
在这里,res.json()返回了一个Promise对象,在这个Promise对象的then方法中我们可以访问到被解析成JSON格式的数据,这时候我们才可以使用这些数据,因此要一个Promise链,总共调用两次then方法。
如果你喜欢最新的async/await语法,我们也可以换一种风格完成同样的事情,就像这样:
(async () => {
const res = await fetch('https://raw.githubusercontent.com/DaKoala/fetch-example/master/people.json');
const json = await res.json();
console.log(json);
// [{ name: "张三", age: 18 }, { name: "李四", age: 20 }, { name: "王五", age: 22 }]
})();
由于await关键词只能在async函数中出现,所以我在这里写了一个包含async关键词的立即执行函数表达式(IIFE),这个代码的效果与上文出现的Promise风格的代码一致。
如果你想了解async/await相关的知识,可以参考阮一峰老师的书籍。
在浏览器中用fetch获取数据
让我们继续使用刚才的JSON文件,这次我们在浏览器中进行同样的操作,并将结果加进HTML中,也就是说,我们用fetch进行一个AJAX请求。
HTML文件
<h1>Fetch示例</h1>
<div id="container"></div>
JavaScript文件
function fetchClassic() {
fetch('https://raw.githubusercontent.com/DaKoala/fetch-example/master/people.json')
.then(res => res.json())
.then(json => {
const container = document.getElementById('container');
json.forEach(item => {
const element = document.createElement('p');
element.textContent = `${item.name} - ${item.age}岁`;
container.appendChild(element);
});
});
}
如果你喜欢async/await风格,你可以这样写:
async function fetchAsync() {
const res = await fetch('https://raw.githubusercontent.com/DaKoala/fetch-example/master/people.json');
const json = await res.json();
const container = document.getElementById('container');
json.forEach(item => {
const element = document.createElement('p');
element.textContent = `${item.name} - ${item.age}岁`;
container.appendChild(element);
});
}
fetchAsync();
运行结果(两种风格的JavaScript代码结果是一样的):
const data = { name: 'Billy', age: 18 };
fetch('https//example.billyzou.com/post', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringfy(data), // "{"name":"Billy","age":18}"
})
如果我们用form的格式提交表单:
const data = { name: 'Billy', age: 18 };
function formatData(data) {
const result = Object.entries(data).map(([key, value]) => `${key}=${value}`).join('&');
return result;
}
fetch('https//example.billyzou.com/post', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: formatData(data), // "name=Billy&age=18"
})
注意两种方法中由于数据格式不同,请求头中的Content-Type字段对应被设置为了application/json和application/x-www-form-urlencoded,在实际操作时请根据你的选择来设置对应的请求头,以便服务器能正确地接收数据。