美文网首页
说说AJAX

说说AJAX

作者: Jason_Shu | 来源:发表于2018-10-15 11:24 被阅读0次

    之前讲了讲JSONP,主要就是发请求的问题。本文会慢慢说明啥是AJAX,然后自己实现一个AJAX,同时介绍下Promise优化。

    1. 我们回顾下,如何发请求?

    用 form 可以发请求,但是会刷新页面或新开页面
    用 a 可以发 get 请求,但是也会刷新页面或新开页面
    用 img 可以发 get 请求,但是只能以图片的形式展示
    用 link 可以发 get 请求,但是只能以 CSS、favicon 的形式展示
    用 script 可以发 get 请求,但是只能以脚本的形式运行

    那么有没有什么方式:

    1. 无论get, post, put, delete请求方式都可以。
    2. 想以什么方式展示就以什么方式展示呢

    就是我们主角啦:AJAX

    1. 使用XMLHttpRequest发送请求。
    2. 服务器返回XML(JSON)格式的字符串。(注意是字符串哟,可不是对象)
    3. JS解析XML(JSON),并更新局部页面。

    还是先上server.js代码:

    var http = require('http')
    var fs = require('fs')
    var url = require('url')
    var port = process.argv[2]
    
    if(!port){
        console.log('请指定端口号好不啦?\nnode server.js 8888 这样不会吗?')
        process.exit(1)
    }
    
    var server = http.createServer(function(request, response){
        var parsedUrl = url.parse(request.url, true)
        var pathWithQuery = request.url
        var queryString = ''
        if(pathWithQuery.indexOf('?') >= 0){ queryString = pathWithQuery.substring(pathWithQuery.indexOf('?')) }
        var path = parsedUrl.pathname
        var query = parsedUrl.query
        var method = request.method
    
        /******** 从这里开始看,上面不要看 ************/
    
        console.log('方方说:含查询字符串的路径\n' + pathWithQuery)
    
        if(path === '/'){
            var string = fs.readFileSync("./index.html");
            response.statusCode = 200
            response.setHeader('Content-Type', 'text/html;charset=utf-8')
            response.write(string);
            response.end()
        } else if(path === "/main.js") {
            var script = fs.readFileSync("./main.js");
            response.statusCode = 200;
          response.setHeader("Content-type", "text/javascript");
          response.write(script);
          response.end();
        } else if(path === "/xxx") {
            response.statusCode = 200;
            response.setHeader("Content-type", "text/json; charset=utf-8");
            response.write(`{    // 此处返回一个JSON对象形式的字符串
                "node": {
                    "name": "Jason",
                    "age": "23"
                }
            }`);
            response.end();
        } else{
            response.statusCode = 404
            response.setHeader('Content-Type', 'text/html;charset=utf-8')
            response.write('呜呜呜')
            response.end()
        }
    
        /******** 代码结束,下面不要看 ************/
    })
    
    server.listen(port)
    console.log('监听 ' + port + ' 成功\n请用在空中转体720度然后用电饭煲打开 http://localhost:' + port)
    

    html代码:

    <button id="myButton">Click me!</button>
    

    main.js代码:

    myButton.addEventListener("click", function() {
        var request = new XMLHttpRequest();
        request.open("GET", "/xxx");  // 配置request
        request.onreadystatechange = function() {
            if(request.readystate === 4) {
                if(request.status >= 200 && request.status < 300) {
                    console.log("success")
                } else {
                    if(request.status > 400) {
                        console.log("fail")
                    }
                }
            }
        };
        request.send();
    });
    

    我们点击按钮后,会有请求到"/xxx",并返回JSON形式的字符串。


    image.png
    image.png

    我们看到在接口中返回的一些数据,但是我们前端怎么获取这些数据呢?

    myButton.addEventListener("click", function() {
        var request = new XMLHttpRequest();
        request.open("GET", "/xxx");  // 配置request
        request.onreadystatechange = function() {
            if(request.readyState === 4) {
                console.log(request)
                if(request.status >= 200 && request.status < 300) {
                    console.log("请求成功!");
                    console.log(request.responseText);
                } else if(request.status >= 400) {
                    console.log("请求失败!")
                }
            }
        };
        request.send();
    });
    

    看上述代码,在request.open()和request.send()之间多了一个request.onreadystatechange的属性,request.readyState会从0变到4(请求完成)。

    1. JS 可以设置任意请求 header 吗?
      第一部分:request.open("get", "/xxx");
      第二部分:request.setHeader("Content-type", "x-www-form-urlencoded");
      第四部分:request.send("name=Jason&age=23")

    2.JS 可以获取任意响应 header 吗?
    第一部分: response.status(状态码) / response.statusText
    第二部分: response.getAllResponseHeaders() (获取响应的所有第二部分内容) / response.getResponseHeader(key) ( 获取第二部分中部分内容,比如response.getResponseHeader("Content-type") )
    第四部分: request.responseText

    接下来我们来封装下AJAX。

    
    // 这是我们以前自己封装jQuery的例子
    window.jQuery = function(nodeOrSelector) {
        let nodes = {};
        nodes.addClass = function() {};
        nodes.html = function() {};
        return nodes;
    }
    
    window.$ = window.jQuery;
    
    
    //  接下来我们自己封装下AJAX
    window.jQuery.ajax = function(url, method, body, successFn, failFn) {
        let request = new XMLHttpRequest();
        request.open(method, url);    //  配置request
        request.setRequestHeader('content-type','x-www-form-urlencoded');
        request.onreadystatechange = function() {
            if(request.readyState === 4) {  //  加载完成
                if(request.status >= 200 && request.status < 300) {
                    successFn.call(undefined, request.responseText);
                } else if(request.status > 400) {
                    console.log("请求失败!");
                    failFn.call(undefined, request);
                }
            }
        };
        request.send(body);
    };
    
    myButton.addEventListener("click", function() {
        $.ajax(
            "/xxx",
            "GET",
            "name=Jason&age=23",
            () => {
                console.log("success!");
            },
            () => {
                console.log("fail!");
            }
        );
    });
    

    在上述代码中,我们可以看到对myButton监听函数里的ajax函数的参数很杂,很容易忘记参数的对应属性是啥,也就是语义化不明显,我们可以优化下, 同时增加请求的第二部分header属性。

    myButton.addEventListener("click", function() {
        $.ajax({
            url: "/xxx",
            method: "GET",
            header: {
              "Content-type": "x-www-form-urlencoded",
              "Jason": 23
            },
            body: "name=Jason&age=23",
            successFn: () => {
                console.log("success!");
            },
            failFn: () => {
                console.log("fail!");
            }}
        );
    });
    

    我们将属性都放入一个对象,这样显得有结构与层次些,那么在ajax函数定义里面也要有相应的修改。

    window.jQuery.ajax = function(obj) {
        let { url, method, header, body, successFn, failFn } = obj;
        let request = new XMLHttpRequest();
        request.open(method, url);    //  配置request
        // 设置header部分
        for(let key in header) {
            request.setRequestHeader(key, headers[key]);
        }
        request.setRequestHeader('content-type','x-www-form-urlencoded');
        request.onreadystatechange = function() {
            if(request.readyState === 4) {  //  加载完成
                if(request.status >= 200 && request.status < 300) {
                    successFn.call(undefined, request.responseText);
                } else if(request.status > 400) {
                    console.log("请求失败!");
                    failFn.call(undefined, request);
                }
            }
        };
        request.send(body);
    };
    

    然后我们又有如下问题,如果有多个库:

    jason.ajax({
      成功: function() {},
      失败: function() {}
    });
    
    jack.ajax(null, null, null, successFn, failFn);
    
    

    这会有一个问题,如果我们不看文档,我们怎么知道传的参数是什么呢?没有一个规范,那么就有了我们这个Promise规范。我们来看看同上的效果,jQuery库怎么实现的。

    function success(responseText) {
        console.log(responseText)
    }
    
    function fail(request) {
        console.log("fail");
        console.log(request);
    }
    
    
    myButton.addEventListener("click", function() {
        $.ajax({
                url: "/xxx",
                method: "GET",
                body: "name=Jason&age=23",
            }).then(success, fail);
    });
    

    或者直接把success函数和fail函数写进then函数里面,作为参数:

    myButton.addEventListener("click", function() {
        $.ajax({
                url: "/xxx",
                method: "GET",
                body: "name=Jason&age=23",
            }).then(
                (responseText) => {
                    console.log(responseText)
                },
                (request) => {
                    console.log("fail");
                    console.log(request);
                });
    });
    

    如果我们想在success函数里进行多个操作呢?

    myButton.addEventListener("click", function() {
        $.ajax({
                url: "/xxx",
                method: "GET",
                body: "name=Jason&age=23",
            }).then(
                (responseText) => {
                    console.log(responseText);
                    return "成功";
                },
                (request) => {
                    console.log("fail");
                    console.log(request);
                    return "error";
                }).then(
            (上一次操作的结果) => {
                console.log(上一次操作的结果)
            },
            (上一次操作的结果) => {
                console.log(上一次操作的结果)
            },
        );
    });
    
    image.png
    image.png

    那我们自己怎么封装这种jQuery操作呢?

    // 这是我们以前自己封装jQuery的例子
    window.jQuery = function(nodeOrSelector) {
        let nodes = {};
        nodes.addClass = function() {};
        nodes.html = function() {};
        return nodes;
    }
    
    window.$ = window.jQuery;
    
    //  接下来我们自己封装下AJAX
    window.jQuery.ajax = function(obj) {
        return new Promise(function(resolve, reject) {
            let { url, method, header, body} = obj;
            let request = new XMLHttpRequest();
            request.open(method, url);    //  配置request
            // 设置header部分
            for(let key in header) {
                request.setRequestHeader(key, headers[key]);
            }
            request.setRequestHeader('content-type','x-www-form-urlencoded');
            request.onreadystatechange = function() {
                if(request.readyState === 4) {  //  加载完成
                    if(request.status >= 200 && request.status < 300) {
                        resolve.call(undefined, request.responseText);
                    } else if(request.status > 400) {
                        console.log("请求失败!");
                        reject.call(undefined, request);
                    }
                }
            };
            request.send(body);
        });
    };
    
    
    
    
    myButton.addEventListener("click", function() {
        $.ajax({
                url: "/xxx",
                method: "GET",
                body: "name=Jason&age=23",
            }).then(
            (text) => console.log(text),
            (request) => console.log(request)
        );
    });
    
    image.png image.png

    就是window.jQuery.ajax里面返回一个Promise对象,这个对象的参数是一个函数,分别传resoleve(success函数)和reject(fail函数), 然后把之前的操作全部放入这个函数中。

    相关文章

      网友评论

          本文标题:说说AJAX

          本文链接:https://www.haomeiwen.com/subject/ocxxzftx.html