什么是fetch
??我們之前未状,過(guò)度過(guò)來(lái)都在用ajax俯画,那么什么是 Fetch ,F(xiàn)etch 是新的游覽器對(duì)象, 等同于 XMLHttpRequest對(duì)象 司草。它提供了許多與 XMLHttpRequest 相同的功能艰垂,但被設(shè)計(jì)成更具可擴(kuò)展性和高效性。
ajax
??廢話不多說(shuō)我們來(lái)看一下傳統(tǒng)的ajax埋虹。
var xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE
try {
xhr = new ActiveXObject('Msxml2.XMLHTTP');
} catch (e) {
try {
xhr = new ActiveXObject('Microsoft.XMLHTTP');
} catch (e) {}
}
}
if (xhr) {
xhr.onreadystatechange = () =>{
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log(xhr.responseText); //返回值傳callback
} else {
//failcallback
console.log('There was a problem with the request.');
}
} else {
console.log('still not ready...');
}
};
xhr.open('POST', 'https://www.baidu.com', true);
// 設(shè)置 Content-Type 為 application/x-www-form-urlencoded
// 以表單的形式傳遞數(shù)據(jù)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('username=admin&password=root');
}
??好我們來(lái)做層封裝猜憎,讓他變成我們 jQuery 的 ajax post
如這種形式:
$.ajax({
method: 'POST', //請(qǐng)求方式
url: '/api', //url
data: { username: 'admin', password: 'root' }, //值
success:function(data){ //成功回掉
console.log(data)
},
error:function(err){
console.log(err)
}
})
好的封裝開始:
const $ = {};
$.ajax = (obj)=>{
var xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE
try {
xhr = new ActiveXObject('Msxml2.XMLHTTP');
} catch (e) {
try {
xhr = new ActiveXObject('Microsoft.XMLHTTP');
} catch (e) {}
}
}
if (xhr) {
xhr.onreadystatechange = () =>{
if (xhr.readyState === 4) {
if (xhr.status === 200) {
obj.success(xhr.responseText); //返回值傳callback
} else {
//failcallback
obj.error('There was a problem with the request.');
}
} else {
console.log('still not ready...');
}
};
xhr.open(obj.method, obj.url, true);
// 設(shè)置 Content-Type 為 application/x-www-form-urlencoded
// 以表單的形式傳遞數(shù)據(jù)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send(util(obj.data));//處理body數(shù)據(jù)
}
//處理數(shù)據(jù)
const util = (obj)=>{
var str = ''
for (key in obj){
str += key +'='+obj[key]+'&'
}
return str.substring(0,str.length-1)
}
}
??ok,咱們已經(jīng)封裝完畢搔课,可以使用了胰柑,可是你會(huì)發(fā)現(xiàn),這種書寫方式很混亂爬泥,body柬讨,hearder亂七八糟,還有回掉地獄的問題袍啡。好的fetch出來(lái)了踩官。
fetch的出現(xiàn)
??我們說(shuō)了,一種東西的誕生有它的道理境输,他首先解決了回掉地獄的問題因?yàn)榉祷匾粋€(gè) promise 對(duì)象 蔗牡,對(duì) promise 對(duì)象不是很熟悉的同學(xué)可以看這篇文章: 你就需要這篇文章,帶你搞懂實(shí)戰(zhàn)的 Promise 對(duì)象嗅剖。同樣既然是 promise 對(duì)象我們就可以使用 es7 的 async / await 戳這里辩越。好了廢話不多說(shuō)我們看看最基礎(chǔ)的 fetch 怎么寫吧 。
fetch(url, options).then(function(response) {
// handle HTTP response
}, function(error) {
// handle network error
})
??就是這么方便信粮,就是這么簡(jiǎn)單黔攒。 fetch 會(huì)先發(fā)起一個(gè) option 的請(qǐng)求,確定是否連接成功,然后再發(fā)送正式的請(qǐng)求 亏钩,就好比 xhr.readyState === 4 這個(gè)一個(gè)道理莲绰。那有同學(xué)就問了欺旧,我的邏輯比較復(fù)雜 姑丑。我的 fetch 要加請(qǐng)求頭,參數(shù)我要傳參傳 formData 不是 json辞友。
我們來(lái)看fetch發(fā)送formdata:
fetch(url,{
method:"post",
headers:{
"Content-type":"application:/x-www-form-urlencoded:charset=UTF-8"
},
body:"name=admin&password=123456"
}).then(function(response){
if(response.ok){
response.json().then(json => {
console.log(json.result)
})
}
}).catch(function(err){
console.log("Fetch錯(cuò)誤:"+err);
});
??發(fā)送json格式也非常簡(jiǎn)單栅哀。
fetch(url,{
method:"post",
headers:{
'Content-Type':'application/json; charset=UTF-8'
},
body:JSON.stringify({name:'admin',password:123456})
}).then(function(response){
if(response.ok){
response.json().then(json => {
console.log(json.result)
})
}
}).catch(function(err){
console.log("Fetch錯(cuò)誤:"+err);
});
中止 取消 fetch
瀏覽器已經(jīng)開始為 AbortController 和 AbortSignal 接口(也就是Abort API)添加實(shí)驗(yàn)性支持称龙,允許像 Fetch 和 XHR 這樣的操作在還未完成時(shí)被中止 。請(qǐng)參閱接口頁(yè)面了解更多詳情痴柔。但是目前對(duì)游覽器的支持并不很好疫向,所以我們其實(shí)可以換一種思路搔驼, 取消 fetch 我們可以從另外一個(gè)面入手 ---- 可以取消 promise 。原生的當(dāng)然不行了糯耍,所以我們這里用到了 bluebird温技。
例如多個(gè) fetch:
//傳統(tǒng) promise
var promises = [];
for (var i = 0; i < fileNames.length; ++i) {
promises.push(fs.readFileAsync(fileNames[i]));
}
Promise.all(promises).then(function() {
console.log("done");
});
// Using Promise.map:
import Promise from 'bluebird'
Promise.map(fileNames, function(fileName) {
// Promise.map awaits for returned promises as well.
return fs.readFileAsync(fileName);
}).then(function() {
console.log("done");
});
終止取消多個(gè) fetch:
import Promise from 'bluebird'
Promise.map(fileNames, function(fileName) {
// Promise.map awaits for returned promises as well.
return fs.readFileAsync(fileName).then(()=>{
//如果flag = true 就中斷荒揣。
if (flag){
throw new Error('中斷')
}
});;
}).then(function() {
console.log("done");
}).catch(function (err) {
console.log('Error', err.message)
});
如果取消單個(gè) promise 可以用 .cancel 方法,具體看 bluebird 文檔翻具。
Axios 的出現(xiàn)
??從文檔中我們可以看出為什么這個(gè)會(huì)火 ,axios 他的功能非常強(qiáng)大,包括 取消請(qǐng)求 ,進(jìn)度處理等等挂据。但是我們看的是本質(zhì)還是 ajax ,在基礎(chǔ)上進(jìn)行了封裝和功能的添加
XMLHttpRequests
支持 Promise
//一個(gè)post請(qǐng)求
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
結(jié)語(yǔ)
??其實(shí)我們看出來(lái)掷倔, ajax 和 Axios 在客戶端都是調(diào)用 XMLHttpRequests 對(duì)象 勒葱,而我們的 fetch 是一個(gè)新的游覽器對(duì)象 巴柿。只不過(guò) ajax 和 Axios 區(qū)別就是在 封裝了簡(jiǎn)便的方法广恢,并且提供了一個(gè) promise 對(duì)象。