从ajax到fetch来理解Promise

ajax

原始ajax

一个大家都会使用的ajax

1
2
3
4
5
6
const http = new XMLHttpRequest()
http.addEventListener('load', () => {
console.log(http.response)
})
http.open('GET', 'https://api.github.com/users/ikarosu')
http.send()

简单封装ajax方便使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const ajax = (url, {
method = 'GET',
data = '',
async = true,
dataType = '',
success = () => {},
error = () => {}
}) => {
const http = new XMLHttpRequest()
http.responseType = dataType.toLocaleLowerCase()
http.addEventListener('load', () => {
success(http.response)
})
http.addEventListener('error', () => {
error(http.response)
})
http.open(method, url, async)
http.send(data)
}

使用这个ajax

1
2
3
4
5
6
ajax('https://api.github.com/users/ikarosu', {
dataType: 'json',
success(data) {
console.log(data)
}
})

那么这种使用方式就是使用回调函数,jQuery和微信小程序都采用这种方式封装。事实上,我们可以用Promise的方式来封装。

Promise ajax

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const ajax = (url, {
method = 'GET',
data = '',
async = true,
dataType = '',
success = () => {},
error = () => {}
}) => {
return new Promise((resolve, reject) => {
const http = new XMLHttpRequest()
http.responseType = dataType.toLocaleLowerCase()
http.addEventListener('load', () => resolve(http.response))
http.addEventListener('error', () => reject(http.response))
http.open(method, url)
http.send(data)
})
}

一个不怎么严谨的Promise构造示范:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Promise {
constructor(fn) {
fn(this.resolve, this.reject)
}
then(cb) {
Promise.next = cb
return this
}
catch(cb) {
Promise.err = cb
return this
}
resolve(data) {
Promise.next(data)
}
reject(data) {
Promise.err(data)
}
}

new Promise(function(resolve, reject) {...});
异步执行成功后,用resolve传入数据,失败用reject。
Promise.prototype.then(function() {})
Promise.prototype.catch(function() {})
then和catch都传入一个函数,参数则是resolve和reject的数据。

使用这个ajax

1
2
ajax('https://api.github.com/users/ikarosu', {dataType: 'JSON'})
.then(data => console.log(data))

如果在async函数中,使用await将更加直观

1
2
3
4
5
6
async function main() {
const data = await ajax('https://api.github.com/users/ikarosu', {
dataType: 'JSON'
})
console.log(data)
}

看完这几个demo,有没有想要自己封装一个完整的ajax来用?

使用Fetch API

实际上……现在已经有这样的API了—— Fetch API
fetch(input, init)

init

  • method

请求的方法

  • headers

Headers对象

  • mode

cors、 no-cors 或者 same-origin

  • cache

default 、 no-store 、 reload 、 no-cache 、 force-cache 或者 only-if-cached

  • redirect

follow (自动重定向), error (如果产生重定向将自动终止并且抛出一个错误), 或者 manual (手动处理重定向)

  • referrer

一个 USVString 可以是 no-referrer、client或一个 URL

  • referrerPolicy

no-referrer、 no-referrer-when-downgrade、 origin、 origin-when-cross-origin、 unsafe-url

  • integrity

包括请求的 subresource integrity 值

  • credentials

omit、same-origin 或者 include。如果你需要发送cookie,必须配置该选项。

  • body

可以的类型:ArrayBuffer、ArrayBufferView (Uint8Array and friends)、Blob/File、String、URLSearchParams、FormData

Response

fetch方法返回一个Promise对象,该对象的resolve返回一个respons对象,我们可对该对象进行处理,来返回想要的数据格式。

  • arrayBuffer()
  • blob()
  • json()
  • text()
  • formData()

处理完的数据仍然返回一个Promise对象,resolve则是格式化后的数据,因此我们可以链式调用。

1
2
3
fetch('https://api.github.com/users/ikarosu')
.then(res => res.json())
.then(data => console.log(data))

参考:
Promise –ECMA
Promise –MDN
Promise –阮一峰
Can I Use Promise
Fetch –WhatWG
Fetch –MDN
Can I Use Fetch