前言
emmmm,由于學(xué)習(xí)node
異步的時候研究了一波promise
因此對于使用promise
的fetch
產(chǎn)生了極大的興趣
(忘了原生ajax的寫法orz)
小小總結(jié)一下fetch
的用法
基本api翻翻 MDN 就ok了
支持程度
time: 2017/9/22 0:07:52
基本用法
GET
fetch('/api/user/1').then((res) => {
if (res.ok) {
return res.json() // promise對象
} else {
console.log('error1')
}
})
.then((data) => {
console.log(data)
})
.catch((err) => {
console.log('error2' + err)
})
POST
fetch('/api/user', {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=UTF-8'
},
credentials: 'include' // 用來讓fetch攜帶cookie
body: JSON.stringify({
account: 'cheesekun',
passwd: 'cheesekun'
})
})
.then((res) => {
return res.json()
})
.then((data) => {
console.log(data)
})
封裝fetch
加工了一波別人的封裝
class AjaxFetch {
constructor(opts, params) {
const isUrl = typeof opts === 'string';
this.defaults = {
method: 'GET',
headers: {},
data: {},
credentials: 'include', //默認(rèn)不帶cookie流炕,指定inlude澎现,始終攜帶cookie
cache: 'default',
// mode:''//請求時會自動識別是否跨域仅胞,不需要手動設(shè)置
};
this.options = Object.assign(this.defaults, (isUrl ? params : opts) || {});
this.methods = ['GET', 'PUT', 'PATCH', 'DELETE', 'POST'];
this.url = isUrl ? opts : this.options.url;
this.init();
return isUrl ? this : this[this.options.method.toLowerCase()](this.options.data)
}
init() {
this.methods.forEach(method => {
this[method.toLowerCase()] = data => {
if ('GET' == method) {
this.url += (this.url.includes('?') ? '&' : '?' + this.transformData(data))
} else {
// if (data instanceof FormData) {
// this.options.headers['Content-Type'] = 'multipart/form-data';
// } else
if (typeof JSON.parse(data === 'object')) {
this.options.headers['Content-Type'] = 'application/json;charset=UTF-8';
// 服務(wù)端消息主體是序列化后的 JSON 字符串
} else {
this.options.headers['Content-Type'] = 'application/x-www-form-urlencoded';
}
// this.options.body = this.transformData(data);
this.options.body = data;
}
delete this.options.data;
this.options.method = method;
console.log(this.options)
return fetch(this.url, this.options);
}
})
}
transformData(obj) {
// 這里還需要做更多的處理
if (obj instanceof FormData) return obj;
var params = [];
for (var i in obj) {
params.push(`${i}=${obj[i]}`);
}
return params.join('&');
}
}
function http(opt, pms) {
if (!opt) return;
return new AjaxFetch(opt, pms);
}
調(diào)用
// 原生
fetch('/api/photo', {
method: 'POST',
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: "name=二次元"
}).then((res) => {
return res.json()
})
.then((data) => {
console.log(data)
})
})
// 使用封裝
http({
url: '/api/photo'
method: 'POST',
body: "name=二次元"
})
.then((res) => {
return res.json()
})
.then((data) => {
console.log(data)
})
使用async控制
fetch()
返回的是一個 Response流
,讀取完成剑辫。它返回一個 promise
res.json()
返回一個被解析為JSON格式的promise對象
btn_ajax_http.addEventListener('click', async () => {
let res = await http({
url: 'api/photo',
method: 'POST',
data: JSON.stringify({
name: '二次元'
})
})
let data = await res.json()
console.log(data)
})
fetch下載文件
let btn_photo = document.getElementById('btn-photo')
btn_photo.addEventListener('click', () => {
fetch('./static/bili.jpg').then((res) => {
return res.blob()
})
.then((data) => {
let download = document.getElementById('download-link')
let objURL = URL.createObjectURL(data)
console.log(data)
download.setAttribute('download', data.type)
download.setAttribute('href', objURL)
download.innerText = '來下載看看'
})
})
fetch坑點
fetch 在發(fā)送請求時默認(rèn)不會帶上 Cookie
所以請求參數(shù)要加上credentials: 'include'
{
headers: {},
credentials: 'include' // 用來讓fetch攜帶cookie, 不是寫在請求頭
}
fetch 只有在遇到網(wǎng)絡(luò)錯誤的時候才會 reject 這個 promise饼问,比如用戶斷網(wǎng)或請求地址的域名無法解析等。只要服務(wù)器能夠返回 HTTP 響應(yīng)(甚至只是 CORS preflight 的 OPTIONS 響應(yīng))揭斧,promise 一定是 resolved 的狀態(tài)。
所以要使用res.ok
來判斷是否 200
res方法(如
res.json()
)重復(fù)調(diào)用會報錯
Uncaught TypeError: Already read
結(jié)語
比起ajax
, 使用上async
的fetch
顯得十分簡潔
瀏覽器的支持率也越來越高
基本上現(xiàn)在投身fetch
是沒問題啦??