四时宝库

程序员的知识宝库

fetch-新时代的 Ajax(fetch用法)

jQuery 当初的流行带来了一个很重要的 API 那就是 $.ajax() 相信很多同学都深爱过它,究其原因是原生 XMLHttpRequest 的不友好,只能借助第三方框架来发送 Ajax 请求,近来也出现了更多好用的框架,比如 axios,难道真的就只能借助第三方框架来做这个事吗?

还真不是,新推出的 Fetch API 就是用来替代 XMLHttpRequest 的,功能类似,更具可扩展性和高效性。我们来看一个简单的例子

fetch('https://api.awesomes.cn/repo/top100')
.then(function(response) {
 return response.json()
})
.then(function(data) {
 console.log(data)
})

注意,这和使用 axios 是不一样的,并非一次到位就能拿到响应 body,而是要经过两次 Promise.then(),当然我们可以很容易地将其变成 async await 的方式

let fetchData = async () => {
 let response = await fetch('https://api.awesomes.cn/repo/top100')
 let data = await response.json()
}

fetch() 方法返回的是一个 Response 对象,结构如下

{
 body: ReadableStream,
 bodyUsed: false,
 headers: Headers,
 ok: true
 redirected: false
 status: 200
 statusText: "OK"
 type: "cors",
 url: "https://api.awesomes.cn/repo/top100"
}

这里的响应正文 body 实际上是一个流,很明显是不能直接使用的,只能通过下面的方法来获取不同格式的内容

  • Body.arrayBuffer() 使用 buffer 数组来读取
  • Body.blob() 使用 Blob 对象来读取
  • Body.formData() 使用 FormData 对来读取
  • Body.json() 使用 JSON 对来读取
  • Body.text() 使用文本对来读取

比如下载一张图片并用 <img> 标签显示(注意跨域)

<img id="imgbox">
....
let setImg = async () => {
 let response = await fetch('https://avatars1.githubusercontent.com/in/2740')
 let data = await response.blob()
 let objectURL = URL.createObjectURL(data)
 let myImage = document.querySelector('#imgbox')
 myImage.src = objectURL
}

不管使用上面哪种读取方式,body 只能被读取一次,然后 bodyUsed 的值都会被修改成 true,表示已被使用,之后就不能再读取了。

let fetchData = async () => {
 let response = await fetch('https://api.awesomes.cn/repo/top100')
 console.log('bodyUsed', response.bodyUsed)
 let data = await response.json()
 console.log('bodyUsed', response.bodyUsed)
 let dataAgain = await response.json()
 console.log('dataAgain', dataAgain)
}
fetchData()
// bodyUsed false
// bodyUsed true
// Uncaught (in promise) TypeError: Failed to execute 'json' on 'Response': body stream is locked

可以看到,试图再次读取 body 是会报错的,如果我就是想要多次读取呢?我们可以使用 clone() 方法将 Response对象克隆一个出来

let fetchData = async () => {
 let response = await fetch('https://api.awesomes.cn/repo/top100')
 let clone1 = response.clone()
 let clone2 = response.clone()
 let data = await response.json()
 let data1 = await clone1.json()
 let data2 = await clone2.json()
 console.log(data, data1, data2)
 // [data] [data] [data] 
}

注意,每个克隆的对象也只能用一次,要实现多次读取就只能是克隆多个出来。

fetch() 不是只能发送 GET 请求,所有方法的请求都能发送,这取决于它的第二个参数,我们来看看 fetch 的实际语法

fetch(input[, init])
  • input 一个 URL 或者 Request 对象
  • init 可选参数,请求配置(method:请求方法,headers 请求头 body请求体...)

比如要发送一个 POST 请求

let submit = async () => {
 await fetch(url, {
 method: 'POST',
 body: JSON.stringify(data)
 })
}

当然也可以用 Request 构造一个对象传入 fetch

let submit = async () => {
 let _request = new Request(url, {
 method: 'POST',
 body: JSON.stringify(data)
 }
 await fetch(_request)
}

要让请求携带请求头需要用 Headers() 构造函数来创建一个自己的 headers 对象

let submit = async () => {
 let headers = new Headers({
 'Content-Type': 'application/json'
 })
 headers.append('token', 'xxx')
 fetch(url, {
 method: 'POST',
 body: JSON.stringify(data),
 headers: headers
 })
}

如果我要发送一个表单数据呢?可以通过 FormData() 构造函数基于 form 标签构建一个对象出来

var form = new FormData(document.getElementById('login-form'))
fetch("/login", {
 method: "POST",
 body: form
})

除了 IE(非 Edge)目前主流的浏览器都支持 fetch,如果你有更高的兼容性需求,也可以加上 fetch 的 polyfil:https://github.com/github/fetch

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言
    友情链接