Ajax的替代品Fetch初上手

260 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情

Fetch API简介

Fetch是在window对象上实现的接口,用于发起网络请求,和Ajax性质相同,但在设计上比Ajax更友好,主要体现在:

  • fetch将不同性质的接口放到了不同的对象中,而Ajax所有东西都放在了一起
  • fetch返回Promise对象,解决了Ajax通过回调容易形成回调地狱的窘境

fetch函数

/*
 * @param input 接收一个url字符串或者 Request 对象
 * @param options 请求配置Object,可以参照 Request 对象的options
 * @param return Promise 成功时resolve
 */
function fetch(input, [options]) {
    return Promise
}

发送请求

// fetch默认GET请求,一般传参通过url?传递
fetch('/bff/home').then((res) => {
  return res.text() // 响应结果转为文本,得到一个 Promise
}).then((text) => {
  console.log(text, 'text')
})

发送POST请求,传递json数据

// 发送POST请求
fetch('/test/auth/login', {
  method: 'POST',
  body: JSON.stringify({ // body传参,只能是字符串
      user_id: 123
  }),
  headers: new Headers({ // 设置body格式为json
    'Content-Type': 'application/json'
  })
}).then((res) => {
  return res.json() // 响应结果转为json对象,得到一个 Promise
}).then((json) => {
  console.log(json, 'json')
})

response方法转换响应数据格式

Response对象可以单独实例化,但使用fetch请求完成后得到的就是一个 Response 对象,一般极少会出现自己实例化 Response 的情况

response对象可以通过内置方法来得到响应内容的格式,每一个方法返回的都是一个Promise

fetch('/test/auth/login').then((res) => {
  return res.json() // 得到一个json格式的Promise,最常用,如果接口返回的格式无法转化为json则会报错
  return res.text() // 得到一个text格式的Promise,以文本的形式得到响应数据
  return res.arrayBuffer() // 得到一个buffer格式的Promise
  return res.blob() // 得到一个blob格式的Promise
  return res.formData() // 得到一个formData格式的Promise
}).then(data => {
    console.log('想要的数据格式', data)
})

单独构建请求对象

请求体可以单独构建一个对象,这方便重复发起请求用

var myRequest = new Request('/test/auth/login', {
  method: 'POST',
  body: JSON.stringify({
      user_id: 123
  }),
  headers: new Headers({
    'Content-Type': 'application/json'
  })
});

fetch(myRequest).then((res) => {
  return res.json()
}).then((json) => {
  console.log(json, 'json')
})

Request 对象

new Request(url, options);
  • url表示请求资源的路径,无特殊情况一般为字符串
  • options 是请求的相关配置
const options = {
    method: 'GET', // 请求方式
    
    
    headers: new Headers({
        'Content-Type': 'application/json'
    }), // 请求头,一般为 Headers 实例化对象,或者Object
    
    
    body: JSON.stringify({
      user_id: 123
    }), // 请求的body,格式可以为:[Blob, BufferSource, formData, URLSearchParams, USVString, ReadableStream]
    
    
    mode: 'cors', // 请求方式,默认为cors,允许跨域请求;可选值参考:https://developer.mozilla.org/zh-CN/docs/Web/API/Request/mode
    
    
    credentials: 'omit', // 请求中cookie的处理,默认值为:omit:不发送cookie;可选值为 same-origin:同源时发送,include: 总是发送
    
    cache: 'default', // 请求的缓存方式,参考https://developer.mozilla.org/zh-CN/docs/Web/API/Request/cache
    
    redirect: 'follow',
    referrer: 'client',
    integrity: ''
}

Headers 构造函数

在Request中,设置请求头可以使用一个对象,或者构建一个 Headers 对象,后者的好处主要是Headers类中提供了一些方法给我们:

var myHeaders = new Headers({
    'Content-Type': 'application/json'
});

// 添加一行新的请求头,如果key重名,检查是否接受多个值,如果接受则添加到value后面
myHeaders.append('Access-Token', token);


// 移除一行请求头
myHeaders.delete('Access-Token');


// 得到headers的可迭代对象
var list = myHeaders.entries() 
for (var pair of list) {
   console.log(pair[0]+ ': '+ pair[1]);
}


// 获取headers的某一项
myHeaders.get('Access-Token');


// 判断headers是否具有某一项
myHeaders.has('Access-Token');


// 得到headers的key可迭代对象
myHeaders.keys();


// 得到headers的values可迭代对象
myHeaders.keys();


// 设置headers的某一项,如果不存在则添加,如果存在则整个覆盖
myHeaders.set('Access-Token');

取消请求

fetch请求可以通过 AbortController 对象进行中止,但需要注意的是 AbortController 兼容性并不是特别好。

// 构建一个 AbortController对象,并获取该对象的标志
const controller = new AbortController();
let signal = controller.signal;

// 把标志传递给fetch配置,如果取消了fetch会进入reject
fetch('/list', { signal }).then(function(response) {
    //...
}).catch(function(e) {
    reports.textContent = 'Download error: ' + e.message;
})


// 通过 AbortController对象取消请求
controller.abort()

和axios相比

axios是一套成熟的请求库,在原生ajax的基础上做了功能的完善和拓展,而fetch只是基础的api,能和ajax相比,但axios作为插件库,和fetch严格上并不属于同一级别,axios兼容性和功能性都不是fetch可比的。

  • axios可以在node服务端使用,而fetch是挂载到window对象上的,只支持浏览器中使用
  • axios封装了请求前和请求后的拦截钩子,fetch原生并没有这种实现
  • axios有独立的不同的请求函数,如get、post等,fetch全靠配置
  • ...

总之,fetch和axios并不是一种类别的东西,也许有一天,会有一款基于fetch的请求库比axios更优秀,也许有一天axios会采用fetch实现。

什么时候应该使用

  • 简单的演示项目,不含复杂请求的demo
  • 技术生态中有基于fetch封装的插件,如vueuse/useFetch
  • ...

参考资料

MDN Fetch MDN AbortController