只要用過(guò) Vue蒋院,沒(méi)人會(huì)不知道 axios 這個(gè)庫(kù),他基乎取代了 jQuery 發(fā) ajax 的功能了参淹。今天我就用 Promise 來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 axios。
純 JS 發(fā) ajax
使用純 JS 發(fā) ajax 要 4 步偿曙。
- 創(chuàng)建 XMLHttpRequest 對(duì)象
- 使用
open
函數(shù) - 設(shè)置
onreadystatechange
回調(diào) - 使用
send
傳入請(qǐng)求數(shù)據(jù)
const xhr = new XMLHttpRequest()
xhr.open(method, url)
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
resolve(xhr.response)
} else {
reject(xhr.statusText)
}
}
xhr.send(data)
上面的寫(xiě)法的對(duì)的,但是在 Promise 里是有坑的羔巢,下面會(huì)說(shuō)到望忆。
引入 Promise
Promise 傳入?yún)?shù)為一個(gè)函數(shù),而這個(gè)函數(shù)里面兩個(gè)參數(shù)分別是 resolve 函數(shù)和 reject 函數(shù)朵纷。
- 當(dāng) Promise 狀態(tài)變成 fulfilled 時(shí)(成功)炭臭,就調(diào)用 resolve
- 當(dāng) Promise 狀態(tài)變成 rejected 時(shí)(失敗)袍辞,就調(diào)用 reject
所以我們可能會(huì)寫(xiě)下在的代碼:
new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.open(method, url)
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
resolve(xhr.response)
} else {
reject(xhr.statusText)
}
}
xhr.send(data)
})
注意鞋仍,這里創(chuàng)建 Promise 對(duì)象的時(shí)候就會(huì)立刻,馬上去執(zhí)行 Promise 傳入那個(gè)函數(shù)里的代碼搅吁。但是 resolve 和 reject 還不會(huì)調(diào)用威创,現(xiàn)在 Promise 會(huì)進(jìn)入 pending (等待)狀態(tài)。
如果請(qǐng)求成功再去調(diào)用 resolve(此時(shí) pending 變成 fulfilled)谎懦,如果失敗會(huì)去調(diào)用 reject(此時(shí) pending 變成 rejected)肚豺。
坑
就像我前面說(shuō)的,這里有一個(gè)坑〗缋梗現(xiàn)在的想法是希望 readyState 為 4(已經(jīng)響應(yīng)了)且 stats 為 200 (響應(yīng)成功了)就去調(diào)用 resolve 函數(shù)吸申。
首先我們要知道 Promise 的一個(gè)規(guī)則是:只要 Promise 狀態(tài)一改變就不會(huì)再去改變了。但是 onreadystatechange 是會(huì)一直被調(diào)用的。
他會(huì)一直查看 readyState 的值截碴,直到 readyState === 4 為止才不會(huì)再去調(diào)用 onreadystatechange 的回調(diào)梳侨。如果現(xiàn)在 readyState === 2 時(shí),按現(xiàn)在的代碼會(huì)去調(diào)用 reject(xhr.statusText)
日丹,Promise 的狀態(tài)就會(huì)立馬變成 rejected走哺,狀態(tài)一旦確定就不會(huì)再改變了,也就是說(shuō)整個(gè)代碼下來(lái)只調(diào)用了 reject哲虾。
正確的寫(xiě)法應(yīng)該是 readyState < 4 都不去調(diào)用丙躏,只有 4 時(shí)再去調(diào)用。
new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.open(method, url)
xhr.onreadystatechange = () => {
if (xhr.readyState !== 4) {
return
}
if (xhr.status === 200) {
resolve(xhr.response)
} else {
reject(xhr.statusText)
}
}
xhr.send(data)
})
包裝
解決這個(gè)坑后我們應(yīng)該把上面的代碼包裝到一個(gè)函數(shù)里束凑。
function axios(ajaxObj) {
const {url, method, data} = ajaxObj
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.open(method, url)
xhr.onreadystatechange = () => {
if (xhr.readyState !== 4) {
return
}
if (xhr.status === 200) {
resolve(xhr.response)
} else {
reject(xhr.statusText)
}
}
xhr.send(data)
})
}
使用的時(shí)候就可以用 .then()
來(lái)使用了晒旅。
function sendRequest() {
const ajaxObj = {
url: 'https://cnodejs.org/api/v1/topics',
method: 'GET',
data: ''
}
axios(ajaxObj)
.then((response) => {
console.log('resolve')
console.log(response)
})
.catch((error) => {
console.error(error)
})
}