實現(xiàn)一個AJAX

AJAX是什么鬼 續(xù)篇

今天我們給AJAX封裝一下

之前寫了篇有關(guān)用原生JS寫jQuery的博客
下面是相關(guān)主要代碼

window.jQuery = function (nodeOrSelector) {
    let nodes = {}
    nodes.addClass = function () {}
    nodes.html = function () {}
    return nodes
}

事實上就是用函數(shù)給代碼封裝一下并設(shè)定相關(guān)參數(shù)

window.jQuery.ajax = function (url, method, body, succseeFn, failFn) {
    let request = new XMLHttpRequest()
    //初始化請求
    request.open(method, url)
    request.onreadystatechange = () => {
        if (request.readyState === 4) {
            if (request.status >= 200 && request.status < 300) {
                succseeFn.call(undefined, request.responseText)
            } else if (request.status >= 400) {
                failFn.call(undefined, request)
            }
        }
    }
    request.send(body)
}
window.$ = window.jQuery

可以使用$.ajax了

myButton.addEventListener('click', (e) => {
    $.ajax(
        '/ada',
        'post',
        'a=1&b=2',
        (responseText) => {
            console.log('s')
        },
        (request) => {
            console.log('f')
        })
})

但是這個$.ajax依然有問題
1.給定的參數(shù)順序太死
如果我不傳其中一個參數(shù),就需要給這個參數(shù)所在位置占位傅联,如若method是'get'先改,就不返回body,那就需要用undefined等占位

'/ada',
'post',
//null蒸走,undefined或'' 占位
'',
(responseText) => {
      console.log('s')
},
(request) => {
      console.log('f')
})

2.無法直觀解釋參數(shù)意思仇奶。
比如上面代碼,如果你沒看過前面內(nèi)容或者原生JS代碼比驻,你都不知道這些參數(shù)分別表達(dá)的是什么意思该溯。

解決方法:給參數(shù)命名唄

window.jQuery.ajax = function (options) {
    //給參數(shù)一個選項
    let method = options.method
    let url = options.url
    let body = options.body
    let succseeFn = options.succseeFn
    let failFn = options.failFn

    let request = new XMLHttpRequest()
    //初始化請求
    request.open(method, url)
    request.onreadystatechange = () => {
        if (request.readyState === 4) {
            if (request.status >= 200 && request.status < 300) {
                succseeFn.call(undefined, request.responseText)
            } else if (request.status >= 400) {
                failFn.call(undefined, request)
            }
        }
    }
    request.send(body)
}

myButton.addEventListener('click', (e) => {
    //以對象的形式傳參數(shù)
    $.ajax({
        url: '/ada',
        method: 'post',
        body: 'a=1&b=2',
        succseeFn: (responseText) => {
            console.log('s')
        },
        failFn: (request) => {
            console.log('f')
        }
    })
})

加一個 setRequestHeader:設(shè)置請求第二部分

headers: {
    'content-type':'application/x-www-form-urlencoded'
}

$.ajax 部分遍歷一下 headers

let headers = options.headers
//下面代碼放在 requset.open() 后
for (let key in headers) {
    let value = headers[key]
    request.setRequestHeader(key, value)
}


如何向 $.ajax 傳兩個參數(shù):如 jQuery.ajax( url [, options ] )

let url
if(arguments.length === 1){
    url = options.url
}else if(arguments.length === 2){
    url = arguments[0]
    options = arguments[1]
}

現(xiàn)在我們的$.ajax 已經(jīng)和jQuery的一樣了


優(yōu)化一下代碼岛抄,先不管兩個參數(shù)那個

1.ES6的 解構(gòu)賦值

//這6行代碼太丑了
let url= options
let method = options.method
let body = options.body
let succseeFn = options.succseeFn
let failFn = options.failFn
let headers = options.headers
//用ES6解構(gòu)賦值,上面代碼等價于
let = {url,method,body,headers,successFn,failFn} = options 

可以不要 options 了

window.jQuery.ajax = function ({url,method,body,headers,succseeFn,failFn}){}

2.Promise,相關(guān)知識可以參考
之前我們給參數(shù)命名了狈茉,我是知道了這個參數(shù)代表什么夫椭。
但是每個人的命名都會不一樣,比如 jQuery 的 ajax 對響應(yīng)成功的命名就是 success 而我的是 successFn氯庆。
這對于不熟悉對應(yīng)文檔的人來說蹭秋,使用十分不便。
針對這個問題点晴,就有了 Promise
Promise的形式

window.Promise = function(fn){
    //...
    return {
        then:function(){}
    }
}

用Promise函數(shù):resolve,reject 替換 successFn 和 failFn感凤,這個兩個參數(shù)是ES6規(guī)定的,這樣就不會有上述問題了
return new Promise(function(resolve,reject){})

window.jQuery.ajax = function ({url,method,body,headers}) {
    //之前代碼返回值是 undefined粒督,我們return一個Promise
    return new Promise(function(resolve,reject){
        let request = new XMLHttpRequest()
    //初始化請求
    request.open(method, url)
    for (let key in headers) {
        let value = headers[key]
        request.setRequestHeader(key, value)
    }
    request.onreadystatechange = () => {
        if (request.readyState === 4) {
            if (request.status >= 200 && request.status < 300) {
                // successFn 就由 resove 代替了
                resolve.call(undefined, request.responseText)
            } else if (request.status >= 400) {
                // failFn 就由 reject 代替了
                reject.call(undefined, request)
            }
        }
    }
    request.send(body)
    })
}

window.$ = window.jQuery

myButton.addEventListener('click', (e) => {
    //以對象的形式傳參數(shù)
    $.ajax({
        url: '/ada',
        method: 'post',
        headers: {
            'content-type': 'application/x-www-form-urlencoded',
            'ada': '18'
        }
    }).then(
        //成功后執(zhí)行的代碼
        (responseText)=>{console.log(responseText)},
        //失敗后執(zhí)行的代碼
        (request)=>{console.log(request)}
      )
})

then 后再 then

.then(
    //成功后執(zhí)行的代碼
    (responseText)=>{console.log(responseText);return '處理成功'}, 
    //失敗后執(zhí)行的代碼
    (request)=>{console.log(request);return '處理失敗'}
    ).then(
    //上一次成功后的return
    (responseText)=>{console.log(responseText)},
    //上一次失敗后的return
    (request)=>{console.log(request)}
)

可以看下結(jié)果

完整代碼請看 github


小記

AJAX 的所有功能
客戶端的JS發(fā)起請求(瀏覽器上的)
服務(wù)端的JS發(fā)送響應(yīng)(Node.js上的)
1.JS 可以設(shè)置任意請求 header
第一部分 request.open(method, url)
第二部分 request.setRequstHeader('content-type','application/x-www-form-urlencoded')
第四部分 request.send(body)
2.JS 可以獲取任意響應(yīng) header
第一部分 request.status / request.statusText
第二部分 request.getResponseHeader() / request.getAllResponseHeaders()
第四部分 request.responseText
圖解

有關(guān)回調(diào) (callback:打電話回來):

succseeFn.call(undefined, request.responseText)
//這種形式就是回調(diào)
succseeFn: () => {}

promise 的 .then() 和 .then().then() 理解

.then(
  fn1,fn2
).then(
  fn3,fn4
  )

.then( , ) 逗號左邊為成功執(zhí)行陪竿,右邊為失敗執(zhí)行
我們可以稱第一個: .then( fn1 , fn2 )為第一負(fù)責(zé)人;第二個: .then( fn3 , fn4 )為第二負(fù)責(zé)人
第一負(fù)責(zé)人成功則執(zhí)行 fn1 屠橄,失敗則執(zhí)行 fn2族跛;第一負(fù)責(zé)人處理完成處理則第二負(fù)責(zé)人執(zhí)行 fn3 ,處理不好(如代碼有問題)則執(zhí)行 fn4


本文僅供個人學(xué)習(xí)使用

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末锐墙,一起剝皮案震驚了整個濱河市礁哄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌溪北,老刑警劉巖桐绒,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異之拨,居然都是意外死亡茉继,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進(jìn)店門蚀乔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來烁竭,“玉大人,你說我怎么就攤上這事吉挣∨伤海” “怎么了?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵睬魂,是天一觀的道長终吼。 經(jīng)常有香客問我,道長氯哮,這世上最難降的妖魔是什么际跪? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上垫卤,老公的妹妹穿的比我還像新娘威彰。我一直安慰自己,他們只是感情好穴肘,可當(dāng)我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布歇盼。 她就那樣靜靜地躺著,像睡著了一般评抚。 火紅的嫁衣襯著肌膚如雪豹缀。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天慨代,我揣著相機(jī)與錄音邢笙,去河邊找鬼。 笑死侍匙,一個胖子當(dāng)著我的面吹牛氮惯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播想暗,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼妇汗,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了说莫?” 一聲冷哼從身側(cè)響起杨箭,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎储狭,沒想到半個月后互婿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡辽狈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年慈参,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片稻艰。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡懂牧,死狀恐怖侈净,靈堂內(nèi)的尸體忽然破棺而出尊勿,到底是詐尸還是另有隱情,我是刑警寧澤畜侦,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布元扔,位于F島的核電站,受9級特大地震影響旋膳,放射性物質(zhì)發(fā)生泄漏澎语。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望擅羞。 院中可真熱鬧尸变,春花似錦、人聲如沸减俏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽娃承。三九已至奏夫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間历筝,已是汗流浹背酗昼。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留梳猪,地道東北人麻削。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像春弥,于是被迫代替她去往敵國和親碟婆。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,834評論 2 345