推薦閱讀地址
掘金
求 start
大家好,我是林一一范删,下面這篇文章是關(guān)于 Ajax蕾域,fetch,axios的超高頻面試題到旦,一起來閱讀吧??
思維導(dǎo)圖
一旨巷、Ajax
1. 概念
Ajax全稱:async javaScript and xml。xml:是一種可以擴(kuò)展的文本標(biāo)記語言添忘,可以擴(kuò)展自定義的語義標(biāo)簽采呐。很早以前 xml 常用于從服務(wù)端返回?cái)?shù)據(jù)結(jié)構(gòu),現(xiàn)在基本都是使用 json 格式返回?cái)?shù)據(jù)搁骑。
2. 作用
在不刷新全局的條件下斧吐,局部刷新頁面。
3. 四步創(chuàng)建 Ajax
- 創(chuàng)建
Ajax
實(shí)例仲器,let xhr = new XMLHttpRequest()
煤率,IE6 不兼容這種寫法 - 打開請(qǐng)求,配置請(qǐng)求前的配置項(xiàng)乏冀,共 5個(gè)參數(shù)蝶糯,
xhr.open([http method], [url], [async], [userName], [userPass])
http methods
有常用的請(qǐng)求方式有,post, get, delete, put, head, options, trace, connect
辆沦。async
代表異步昼捍,默認(rèn)是true
異步,false
是同步肢扯。[url]
:是想服務(wù)器請(qǐng)求的api
妒茬。[userName], [userPass]
,代表用戶名和密碼
- http methods 細(xì)分:delete:刪除服務(wù)器端的某些數(shù)據(jù)蔚晨,一般是文件乍钻。put:向服務(wù)器上存放某些內(nèi)容,一般是文件,head:只是獲取從服務(wù)器端返回的請(qǐng)求頭信息团赁,不要響應(yīng)主體的內(nèi)容育拨。options:一般用于向服務(wù)器發(fā)送探測(cè)性請(qǐng)求,看是否連接成功
- 事件監(jiān)聽
readystatechange
欢摄,一般監(jiān)聽 ajax 狀態(tài)碼發(fā)生改變的事件熬丧,這個(gè)事件可以獲取服務(wù)器返回的響應(yīng)主和請(qǐng)求頭。xhr.onreadystatechange = function (){}
怀挠,對(duì)于同步
執(zhí)行的 Ajax 請(qǐng)求代碼步驟三要放在send
的前面析蝴。否則沒有意義。 - 發(fā)送 ajax 請(qǐng)求绿淋,ajax 任務(wù)開始執(zhí)行闷畸。
xhr.send([])
,XMLHttpRequest.send()
方法中如果 Ajax 請(qǐng)求是異步的則這個(gè)方法發(fā)送請(qǐng)求后就會(huì)返回吞滞,如果Ajax請(qǐng)求是同步的佑菩,那么請(qǐng)求必須知道響應(yīng)后才會(huì)返回。
第五步算上的話裁赠,就是讀取返回的數(shù)據(jù)
xhr.responseText
殿漠。
// 1. 創(chuàng)建 XMLHttpRequest 實(shí)例
let xhr = XMLHttpRequest()
// 2. 打開和服務(wù)器的連接
xhr.open('get', 'URL')
// 3.發(fā)送
xhr.send()
// 4. 接收變化。
xhr.onreadystatechange = () => {
if(xhr.readyState == 4 && xhr.status == 200){ // readyState: ajax 狀態(tài)佩捞,status:http 請(qǐng)求狀態(tài)
console.log(xhr.responseText); //響應(yīng)主體
}
}
4. Ajax 狀態(tài)和 HTTP 狀態(tài)碼
- Ajax 狀態(tài)一共有 5 種
xhr.readyState
绞幌,分別是0, 1, 2, 3, 4
- 狀態(tài) 0:
unsent
,剛創(chuàng)建的XMLHttpRequest
實(shí)例一忱,還沒有發(fā)送莲蜘。- 狀態(tài) 1:(載入)已調(diào)用
send()
方法,正在發(fā)送請(qǐng)求帘营。- 狀態(tài) 2:(載入完成)
send()
方法執(zhí)行完成票渠,已經(jīng)接收到全部響應(yīng)內(nèi)容- 狀態(tài) 3:
loading
,(交互)正在解析響應(yīng)內(nèi)容- 狀態(tài) 4:
done
仪吧,表示響應(yīng)的主體內(nèi)容解析完成庄新,可以在客戶端調(diào)用了
- HTTP 常見的狀態(tài)碼鞠眉。
2xx
:表示請(qǐng)求已經(jīng)被服務(wù)器接收薯鼠,理解,請(qǐng)接受械蹋。常見的有出皇,200
表示ok,表示服務(wù)能夠返回信息哗戈。204
No Content 無內(nèi)容郊艘。服務(wù)器成功處理,但未返回內(nèi)容。3xx
:一類重要的高頻考點(diǎn)纱注,301
:表示永久轉(zhuǎn)移畏浆,返回舊域名會(huì)跳轉(zhuǎn)到心域名。302
:臨時(shí)轉(zhuǎn)移狞贱。一般用于服務(wù)器負(fù)載均衡刻获,但服務(wù)器的并發(fā)數(shù)達(dá)到最大時(shí),服務(wù)器會(huì)將后續(xù)訪問的用戶轉(zhuǎn)移到其他服務(wù)器上去瞎嬉。307
:表示臨時(shí)重定向蝎毡。304
:表示不設(shè)置緩存,對(duì)于不經(jīng)常更新的文件氧枣,例如css/js/html文件
沐兵,服務(wù)器會(huì)結(jié)合客戶端設(shè)置304
狀態(tài),加載過的資源下次請(qǐng)求時(shí)會(huì)在客戶端中獲取便监。4xx
:表示語義有誤扎谎,請(qǐng)求無法被服務(wù)器端理解。400
:表示請(qǐng)求的參數(shù)錯(cuò)誤烧董。401
:表示無權(quán)限訪問簿透。404
:表示請(qǐng)求的資源不存在。413
:表示和服務(wù)器的交互過大解藻。5xx
:服務(wù)器端出錯(cuò)老充。500
:表示服務(wù)器端出現(xiàn)未知的錯(cuò)誤。503
:服務(wù)器超負(fù)荷螟左。
5. ajax 中常用的屬性和方法
onabort
: 表示請(qǐng)求中斷后要處理的事啡浊。和xhr.abort()
一起使用。ontimeout
: 表示請(qǐng)求的超時(shí)胶背,執(zhí)行的方法巷嚣。和timeout
設(shè)定的事件一起使用。response
: 響應(yīng)的主體內(nèi)容钳吟。responseText
: 響應(yīng)的具體內(nèi)容是字符串廷粒,一般是 json 字符串responseXML
: 響應(yīng)的具體內(nèi)容是文檔。status
: http 的狀態(tài)碼红且。statusText
: 狀態(tài)碼描述withCredentials
:表示是否允許跨域坝茎。getAllResponseHeaders
:獲取所有響應(yīng)頭信息。xhr.open()
:打開URL請(qǐng)求暇番。xhr.send()
:表示發(fā)送 ajax嗤放。setRequestHeader()
: 設(shè)置請(qǐng)求頭。這個(gè)屬性在必須在xhr.open()
后面壁酬。
思考
-
post
和get
有什么區(qū)別次酌。
http
的所有請(qǐng)求方法中都可以從服務(wù)端獲取數(shù)據(jù)恨课,和傳遞內(nèi)容。get
:主要是從服務(wù)器獲取數(shù)據(jù)岳服。post
主要發(fā)送數(shù)據(jù)給服務(wù)器剂公。
GET
和POST
本質(zhì)上就是TCP
鏈接,并無差別吊宋,但是由于HTTP的規(guī)定和瀏覽器/服務(wù)器的限制具體由如下的區(qū)別
- 從
緩存
的角度上說诬留,get
請(qǐng)求會(huì)被瀏覽器默認(rèn)緩存下來,而post
請(qǐng)求默認(rèn)不會(huì)贫母。 - 從
參數(shù)
來說文兑,get
請(qǐng)求的參數(shù)一般放在url
中,post
請(qǐng)求是放在請(qǐng)求主體中腺劣,因此post
請(qǐng)求更安全一些绿贞。 - 從
TCP
上來說,GET
產(chǎn)生一個(gè)TCP
數(shù)據(jù)包橘原;POST
產(chǎn)生兩個(gè)TCP
數(shù)據(jù)包籍铁。對(duì)于GET方式的請(qǐng)求,瀏覽器會(huì)把http header
和data
一并發(fā)送出去趾断,服務(wù)器響應(yīng)200(返回?cái)?shù)據(jù))拒名;而對(duì)于POST
,瀏覽器先發(fā)送header
芋酌,服務(wù)器響應(yīng)100 continue
增显,瀏覽器再發(fā)送data
,服務(wù)器響應(yīng)200 ok(返回?cái)?shù)據(jù))脐帝。雖然 post 請(qǐng)求需要發(fā)送兩次同云,但是時(shí)間上是基本差別不大的。還有并不是所有瀏覽器都會(huì)在POST中發(fā)送兩次包堵腹,Firefox 就只發(fā)送一次
- 來一道思考題炸站,求輸出結(jié)果
let xhr = new XMLHttpRequest()
xhr.open('post', 'api')
xhr.onreadystatechange = () =>{
if(xhr.readyState == 2){
console.log(2)
}
if(xhr.readyState == 4){
console.log(4)
}
}
xhr.send()
console.log(3)
/* 輸出
* 3 2 4
*/
如果知道任務(wù)隊(duì)列的概念,不難知道輸出的結(jié)果疚顷,因?yàn)槭钱惒秸?qǐng)求旱易,所以同步的主任務(wù)先輸出
3
,最后輸出2, 4
腿堤。如果上面xhr.open('post', 'api')
變成xhr.open('post', 'api', false)
后代碼就是同步的阀坏,任務(wù)隊(duì)列中只有主任務(wù)輸出的結(jié)果變成2, 4, 3
。
- 再來一道思考題释液,在同步請(qǐng)求中下面代碼輸出的是什么
let xhr = new XMLHttpRequest()
xhr.open('get', 'xxx', false)
xhr.send()
xhr.onreadystatechange = () => {
console.log(xhr.readyState)
}
上面的結(jié)果什么也沒有輸出全释,這里涉及到任務(wù)隊(duì)列的知識(shí)装处,
onreadystatechange
這個(gè)事件監(jiān)聽的是 ajax 狀態(tài)碼的變化误债,上面的同步請(qǐng)求中xhr.send()
已經(jīng)執(zhí)行完后 ajax 的狀態(tài)碼由 0 變成了 4 還沒有執(zhí)行到onreadystatechange
這個(gè)監(jiān)聽事件浸船,所以沒有輸出結(jié)果。如果將監(jiān)聽事件放在xhr.send()
之前寝蹈,那么輸出的就是 4李命。
二、axios
axios
是使用promise
封裝的ajax
箫老。axios 不是一個(gè)類是一個(gè)方法封字。
1. axios 屬性
axios 有
get, post, put, patch ,delete
等請(qǐng)求方式,get耍鬓,post
返回的實(shí)例都是promise
阔籽,所以可以使用promise
的方法,下面給出基本的實(shí)用方法牲蜀。
-
axios.get()
笆制,向服務(wù)器發(fā)送一個(gè)get
請(qǐng)求。
axios.get('apiURL', {
param: {
id: 1
}
}).then(res=>{
console.log(res);
})
.catch( error=>{
console.log(error)
}
param
中的的鍵值對(duì)最終會(huì)?
的形式涣达,拼接到請(qǐng)求的鏈接上在辆,發(fā)送到服務(wù)器。
-
axios.post()
示例
axios.post('apiURL',{
user: '林一一',
age: 18
}).then( res=>{
console.log(res);
})
.catch( error=>{
console.log(error)
}
-
axios.put()
示例
axios.put('apiURL', {
name: '林一一',
})
-
axios.patch(url[, data[, config]])
示例
axios.patch('apiURL', {
id: 13,
},{
timeout: 1000,
})
-
axios.delete()
示例
axios.delete('apiURL', {
params: {
id: 1
},
timeout: 1000
})
2. 一次并發(fā)的請(qǐng)求 axios.all([])
axios.all()
可以實(shí)現(xiàn)多個(gè)請(qǐng)求度苔,且請(qǐng)求都需要在完成后才再去做某事匆篓。
let requestArr = [axios.get('apiURL/1'), axios.get('apiURL/2'), axios.post('apiURL/3', {id: 3})]
axios.all(requestArr).then(res => {
console.log(res)
})
思考,axios.all() 是怎么實(shí)現(xiàn)并發(fā)請(qǐng)求的寇窑?
axios.all()
使用的是promise.all()
實(shí)現(xiàn)的鸦概,來看看 axios 中的源碼
axios.all = function all(promises) {
return Promise.all(promises);
};
3. axios 中的配置項(xiàng)。
實(shí)用的 axios配置項(xiàng)
三甩骏、fetch
1. 介紹 fetch
-
fetch
:是http
的數(shù)據(jù)請(qǐng)求方式完残,是XMLHttpRequest
的一種代替方案,沒有使用到XMLHttpRequest
這個(gè)類横漏。fetch
不是 ajax谨设,而是原生的 js。fetch()
使用Promise
缎浇,不使用回調(diào)函數(shù)扎拣。fetch
是 ES8 中新增的 api,兼容性不是很好素跺,IE 完全不兼容fetch
寫法二蓝。 -
fetch()
采用模塊化設(shè)計(jì),API 分散在Response
對(duì)象指厌、Request
對(duì)象刊愚、Headers
對(duì)象上。 -
fetch()
通過數(shù)據(jù)流(Stream 對(duì)象)處理數(shù)據(jù),對(duì)于請(qǐng)求大文件或者網(wǎng)速慢的場景相當(dāng)有用妆够。XMLHttpRequest
沒有使用數(shù)據(jù)流,所有的請(qǐng)求都必須完成后才拿到 - 在默認(rèn)情況下
fetch
不會(huì)接受或者發(fā)送cookies
2. fetch(url, optionObj) 基本使用
- 接收第一個(gè)參數(shù)為請(qǐng)求的
url
伴栓,默認(rèn)的請(qǐng)求方式是get
牡借。 - 第二個(gè)是可選參數(shù)
optionObj
拳昌,可以控制不同配置的屬性,比如method:
屬性是字符串钠龙。headers
: 一個(gè)對(duì)象炬藤,可以設(shè)定 http 的請(qǐng)求頭。body
:POST
請(qǐng)求的數(shù)據(jù)體碴里,屬性也是字符串沈矿。credentials
表示是否可以攜帶cookie
,includes
表示是否同源都包含cookie
咬腋。 -
fetch
參數(shù)沒有同步的設(shè)定细睡,因?yàn)?fetch
是基于promise
封裝的本身就是異步。 -
fetch
雖然使用的是promise
封裝的帝火,但是catch
函數(shù)不能直接的捕獲到錯(cuò)誤溜徙,需要在第一個(gè)then
函數(shù)內(nèi)做些操作。
fetch
發(fā)送 post請(qǐng)求時(shí)犀填,當(dāng)發(fā)生的是跨域請(qǐng)求蠢壹,fetch
會(huì)先發(fā)送一個(gè)OPTIONS
請(qǐng)求,來確認(rèn)服務(wù)器是否允許接受請(qǐng)求九巡,這個(gè)請(qǐng)求主要是用來詢問服務(wù)器是否允許修改header頭等一些操作图贸。服務(wù)器同意后返回 204,才會(huì)發(fā)送真正的請(qǐng)求冕广。沒有發(fā)生跨域的情況下不會(huì)產(chǎn)生兩次請(qǐng)求疏日。
一個(gè) get 請(qǐng)求
const pro = fetch('https://lyypro.gitee.io/blog/')
pro.then( response =>
response.json()
).catch( err => {
console.log(err)
})
一個(gè) post 請(qǐng)求
const URL = 'https://lyypro.gitee.io/blog/'
const init = {
method: 'POST',
header: {
"Content-type": "application/x-www-form-urlencoded; charset=UTF-8",
},
data: 'id=12&name=林一一',
credentials: 'include'
}
const pro = fetch(URL, init)
pro.then( response =>
response.json()
).catch( err => {
console.log(err)
})
上面的請(qǐng)求都可以使用
await, async
來修改這里不展示。同時(shí)是為post
請(qǐng)求中撒汉,data
屬性只支持字符串沟优,我們可以使用
4. fetch 的三個(gè)模塊
-
Response
模塊:fetch
請(qǐng)求發(fā)送后,會(huì)得到一個(gè)服務(wù)器的響應(yīng)response
睬辐,這個(gè)響應(yīng)對(duì)于著 http 的回應(yīng)挠阁。 -
Request
模塊:這是用于請(qǐng)求服務(wù)器的模塊,上面提到的data, header, method
都是Request
模塊的屬性溯饵。 -
Headers
侵俗,這是一個(gè)在Response.headers
上的屬性用于操控響應(yīng)頭的信息。
上面三者的詳細(xì)屬性可以看看 阮老師的 Fetch API 教程
5.思考 發(fā)送 post 2 次請(qǐng)求的原因
使用
fetch
發(fā)送post
請(qǐng)求時(shí)如果是跨域丰刊,那么導(dǎo)致fetch
第一次發(fā)送了一個(gè)Options
請(qǐng)求隘谣,詢問服務(wù)器是否支持修改的請(qǐng)求頭啄巧,如果服務(wù)器支持掌栅,則在第二次中發(fā)送真正的請(qǐng)求熄求。
6.思考 fetch 的缺點(diǎn)
fetch
的get/head
請(qǐng)求不能設(shè)置body
屬性渣玲。fetch
請(qǐng)求后逗概,服務(wù)器返回的狀態(tài)碼無論是多少包括(4xx, 5xx),fetch
都不認(rèn)為是失敗的逾苫,也就是使用catch
也不能直接捕捉到錯(cuò)誤,需要再第一個(gè)then
中做一些處理铅搓。
四瑟押、面試題
封裝原生的 Ajax
1.實(shí)現(xiàn)一個(gè) Ajax。
將原生的 ajax 封裝成 promise
var myNewAjax = function (url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open('get', url);
xhr.send(data);
xhr.onreadystatechange = function () {
if (xhr.status == 200 && readyState == 4) {
var json = JSON.parse(xhr.responseText);
resolve(json)
} else if (xhr.readyState == 4 && xhr.status != 200) {
reject('error');
}
}
})
}
2. ajax 有幾個(gè)狀態(tài)多望,分別代表什么氢烘?
ajax 5個(gè)狀態(tài)向上看。
3. fetch VS ajax VS axios 區(qū)別
- 傳統(tǒng)的
ajax
利用的是XMLHttpRequest
這個(gè)對(duì)象椎工,和后端進(jìn)行交互蜀踏。JQuery ajax
是對(duì)原生XHR
的封裝维蒙,多請(qǐng)求間有簽到的話就會(huì)出現(xiàn)回調(diào)地獄的問題果覆。 -
axios
使用promise
封裝xhr
局待,解決了回調(diào)地獄問題 -
fetch
不是XMLHttpRequest
,fetch
是原生的 js燎猛,使用的是promise
。
4. Fetch 和 Ajax 比有什么優(yōu)點(diǎn)沸停?
fetch 使用的是 promise 方便使用異步昭卓,沒有回調(diào)地獄的問題瘟滨。
5. 如何實(shí)現(xiàn)一個(gè) ajax 請(qǐng)求能颁?如果我想發(fā)出兩個(gè)有順序的 ajax 需要怎么做?
實(shí)現(xiàn) ajax 的請(qǐng)求就是上面的創(chuàng)建 ajax 的逼格步驟伙菊。實(shí)現(xiàn)兩個(gè)有順序的 ajax 可以使用
promise.then()
6. Ajax 怎么解決瀏覽器緩存問題
- 設(shè)置請(qǐng)求頭败玉,在 ajax 發(fā)送請(qǐng)求前加上
anyAjaxObj.setRequestHeader("If-Modified-Since","0")
或anyAjaxObj.setRequestHeader("Cache-Control","no-cache")
镜硕。 - 在 URL 后面加上一個(gè)隨機(jī)數(shù):
"fresh=" + Math.random()
。 或在后面加上時(shí)間搓:"nowtTime=" + new Date().getTime()
血淌。 - 如果是使用 jQuery财剖,直接這樣就可以了
$.ajaxSetup({cache:false})
。這樣頁T面的所有 ajax 都會(huì)執(zhí)行這條語句就是不需要保存緩存記錄沦补。
五瞳氓、參考
六、結(jié)束
感謝閱讀到這里店诗,如果著篇文章能對(duì)你有一點(diǎn)啟發(fā)或幫助的話歡迎 star, 我是林一一,下次見音榜。