这是一件很有意思的事,封装一个抽象性函数,就相当于可以把这个函数用在类似相同的环境中。 1、知道AJAX的功能 2、把AJAX的功能封装成函数 3、用Promise优化封装的函数

一、AJAX有哪些功能?

  • 客户端的JS发起请求(浏览器上的)
  • 服务端的JS发送响应(Node.js上的)

1、JS 可以设置任意请求 header 吗?

  • 第一部分 request.open(‘get’, ‘/xxx’)
  • 第二部分 request.setHeader(‘content-type’,‘x-www-form-urlencoded’)
  • 第四部分 request.send(‘a=1&b=2’)

2、JS 可以获取任意响应 header 吗?

  • 第一部分 request.status / request.statusText
  • 第二部分 request.getResponseHeader() / request.getAllResponseHeaders()
  • 第四部分 request.responseText

二、window.jQuery.ajax

之前写过window.jQuery,而这次写window.jQuery.ajax。

封装AJAX函数,JS代码如下:

window.jQuery.ajax = function(obj){
    let url=obj.url
    let method=obj.method
    let body=obj.body
    let successFn=obj.successFn
    let headers=obj.heaaders
    let failFn=obj.failFn
    let request = new XMLHttpRequest()
    request.open(method, url) // 配置request第一部分
    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.call(undefined,x)
                //假如同时调用f1和f2可以这样写这里的x===request.responseText
                //f1.call(undefined,x)
                //f2.call(undefined,x)           
            }else if(request.status >= 400){
                failFn.call(undefined,request)
            }
        }
    }
    request.send(body)//设置请求的第四部分
}

补充一个ES 6的知识点:解构赋值。所以上面声明的前6个let可以用解构赋值来优化代码,到文末的时候我再修改。

var a=1
var b=2;
[a,b]=[2,1]    //a与b的值交换

函数调用方式:

window.jQuery.ajax({
    url:'/xxx',
    method:'post',
    body:'a=1&b=2',
    headers:{
        'content-type':'application/x-www-form-urlencoded',
        'yukaka':'25'
    },
    successFn:function sss(x){console.log(x)},
    failFn:function fff(resquest){console.log('失败了')}  
})

然而successFn 和 failFn 是我定义的。不同的程序员可能回调函数名是不一样,那么在用一个封装过的函数就需要查看手册了传什么样的参数。这不是很方便,那怎么办呢?

三、用Promise来优化函数

用法如下:

const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

用Promise优化AJAX函数:

window.jQuery.ajax = function({url,method,body,headers}){ //这里使用ES6 解构赋值
    return new Promise(function(resolve,reject){   //resolve表示成功,reject表示失败
        let request = new XMLHttpRequest()
        request.open(method, url) // 配置request第一部分
        for(let key in headers){  //遍历,设置请求第二部分
            let value = headers[key];
            request.setRequestHeader(key,value)
        }
        request.onreadystatechange = ()=>{  //获取readyState码
            if(request.readyState===4){
            if(request.status >= 200 && request.status < 300){   //异步操作成功
                  resolve.call(undefined,request.responseText)        
             }else if(request.status >= 400){
                  rejcet.call(undefined,request)
              }
            }
        }
        request.send(body)//设置请求的第四部分
    })
}

函数调用方式:

myButton.addEventListener('click', (e)=>{
    window.jQuery.ajax({
        url:'/xxx',
        method:'post',
        body:'a=1&b=2',
        headers:{
           'content-type':'application/x-www-form-urlencoded',
           'yukaka':'25'
        }    
    }).then(
        (text)=>{console.log("响应成功,调用第一个函数");return 1},//成功调用这个函数       
    ).then(
        (text)=>{console.log(text)},//成功调用这个函数,这里的参数是上一个then返回的值
        (request)=>{console.log('error')} //失败调用这个函数     
    ) 
})

关于then,第一个函数表示的是异步操作成功时调用的函数,第二个函数表示的是失败时调用的函数。同时then接受多个函数的调用,方法就是链式操作。需要注意的是成功调用这个函数,它的参数是上一个then返回的值。

function xxx(){
    return new Promise((f1, f2) => {
        doSomething()
        setTimeout(()=>{
            // 成功就调用 f1,失败就调用 f2
        },3000)
    })
}
xxx().then(success, fail)
xxx().then(success, fail).then(success, fail)  // 链式操作