一、手写AJAX
首先我们先用原生JS手写一个AJAX:
let xhr = new XMLHttpRequest()
xhr.open('POST', '/xxx')
xhr.onreadystatechange = (e) => {
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status < 300){
console.log('请求成功')
}else{
console.log('请求失败')
}
}
}
xhr.send('hi')
这是一个POST请求的AJAX,可以通过修改 open
的第一个参数来修改请求类型,同时 send()
中的参数就是请求的第四部分-请求体(GET请求不需要在 send()
中传参)。
二、封装这个AJAX
我们在实现jQuery中的两个API提到过用函数封装代码的做法,这次一样用一个函数来封装AJAX
window.jQuery.ajax = function(method, url, body, successFn, failFn){
xhr.open(method, url)
xhr.onreadystatechange = ()=>{
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status < 300){
console.log('成功')
successFn.call(undefined, xhr.responseText)
}else{
console.log('失败')
failFn.call(undefined, xhr)
}
}
}
xhr.send(body)
}
window.jQuery.ajax(
'POST',
'/xxx',
'a=1',
(responseText)=>{
console.log(responseText)
},
()=>{
console.log('请求失败')
}
)
这里我们用 window.jQuery.ajax
这个函数来封装第一步中的代码,函数接受五个参数:请求类型、请求的URL、请求体、请求成功时的回调函数、请求失败时的回调函数。
三、改进window.jQuery.ajax
虽然在上一步中我们已经成功封装了一个函数实现AJAX,但是这个函数仍有许多不足,比如我们在使用这个函数的时候并不知道函数的每一个参数代表什么意思,我们只有去看这个函数的源码才知道;再比如我如果使用GET请求,那我不需要在请求中传入请求体,那么函数的第三个参数只能用 null
或 undefined
,并不能直接不传第三个参数。
接下来我们对这个函数作进一步的改进:
window.jQuery.ajax = function(options){
let method = options.method
let url = options.url
let body = options.body
let successFn = options.successFn
let failFn = options.failFn
let xhr = new XMLHttpRequest()
xhr.open(method, url)
xhr.onreadystatechange = ()=>{
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status < 300){
console.log('成功')
successFn.call(undefined, xhr.responseText)
}else{
console.log('失败')
failFn.call(undefined, xhr)
}
}
}
xhr.send(body)
}
myButton.addEventListener('click', function(e){
let obj = {
method: 'post',
url: '/xxx',
body: 'a=1',
successFn: (responseText)=>{
console.log(responseText)
},
failFn: (xhr)=>{
console.log('请求失败')
}
}
window.jQuery.ajax(obj)
})
这里使用了一种参数命名的方法,我们用一个对象表示所有的参数,然后在函数内获取每个具体的参数,这样就可以不用记住参数的顺序,同时能避免少传参数导致错误的情况。
四、为函数添加修改请求头功能
现在我们还缺少一个修改请求头的功能,添加功能后的代码如下:
window.jQuery.ajax = function(options){
let method = options.method
let url = options.url
let body = options.body
let headers = options.headers
let successFn = options.successFn
let failFn = options.failFn
let xhr = new XMLHttpRequest()
xhr.open(method, url)
for(let key in headers){
let value = headers[key]
xhr.setRequestHeader(key, value)
}
xhr.onreadystatechange = ()=>{
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status < 300){
console.log('成功')
successFn.call(undefined, xhr.responseText)
}else{
console.log('失败')
failFn.call(undefined, xhr)
}
}
}
xhr.send(body)
}
myButton.addEventListener('click', function(e){
let obj = {
method: 'post',
url: '/xxx',
body: 'a=1',
headers: {
'Content-Type': 'x-www-foorm-urlencoded',
'xxx': 'yyy'
},
successFn: (responseText)=>{
console.log(responseText)
},
failFn: (xhr)=>{
console.log('请求失败')
}
}
window.jQuery.ajax(obj)
})
在用户传入 headers
对象之后,我们在函数内遍历这个对象,获取它的 key
和 value
,并将这两个值作为参数传入 setRequestHeader()
就完成了修改请求头的功能。
五、简化代码
window.jQuery.ajax = function({method, url, body, headers, successFn, failFn}){
let xhr = new XMLHttpRequest()
xhr.open(method, url)
for(let key in headers){
let value = headers[key]
xhr.setRequestHeader(key, value)
}
xhr.onreadystatechange = ()=>{
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status < 300){
console.log('成功')
successFn.call(undefined, xhr.responseText)
}else{
console.log('失败')
failFn.call(undefined, xhr)
}
}
}
xhr.send(body)
}
直接使用ES6中的解构赋值 {method, url, body, headers, successFn, failFn}
来简化参数。
这样一来,我们就能使用 jQuery.ajax(url,method,body,successFn, failFn)
这样的API了。
六、实现Promise
window.jQuery.ajax = function({method, url, body, headers}){
return new Promise(function(resolve, reject){
let xhr = new XMLHttpRequest()
xhr.open(method, url)
for(let key in headers){
let value = headers[key]
xhr.setRequestHeader(key, value)
}
xhr.onreadystatechange = ()=>{
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status < 300){
console.log('成功')
resolve.call(undefined, xhr.responseText)
}else{
console.log('失败')
reject.call(undefined, xhr)
}
}
}
xhr.send(body)
})
在实现了Promise之后,用户就不需要再考虑回调函数的问题,同时用户也可以使用 then
进行链式操作。
window.jQuery.ajax({
method: 'post',
url: '/xxx',
body: 'a=1'}).then(
(responseText)=>{console.log(responseText)},
(xhr)=>{console.log(xhr)}
)
当请求成功时,控制台会打印出 responseText
,失败时会打印出请求。
以上。
网友评论