[Ajax] A little doubt about the ajax interface of jQuery

A little doubt

Before I came into contact with jQuery's ajax api, I had been encapsulating my interface
code:

// Ajax 封装
function Ajax() {
    
    
    var makeCallback = function (xhr, callback) {
    
    
        xhr.onerror = function (err) {
    
    
            callback(err, undefined, xhr);
        };
        xhr.onload = function () {
    
    
            var contentType = xhr.getResponseHeader('Content-Type');
            callback(undefined, contentType && contentType.indexOf('application/json') != -1
                ? JSON.parse(xhr.responseText)
                : xhr.responseText, xhr);
        };
    };
    var toQueryString = function () {
    
    
        function recursive(value, key) {
    
    
            var queryStr = '';
            if (typeof value != 'object')
                queryStr += key + '=' + value + '&';
            else
                for (var item in value)
                    queryStr += key == undefined ? recursive(value[item], item) : recursive(value[item], key + '[\'' + item + '\']');
            return queryStr;
        }
        return function (value) {
    
    
            return recursive(value).slice(0, -1);
        }
    }();
    this.get = function (options) {
    
    
        options.data = options.data || '';
        var xhr = new XMLHttpRequest();
        options.pre(xhr) && options.pre(xhr);
        makeCallback(xhr, options.callback);
        xhr.open('get', options.url + '?' + (typeof options.data == 'string' ? options.data : toQueryString(options.data)));
        xhr.send();
    };
    this.postUrl = function postUrl(options) {
    
    
        options.data = options.data || '';
        var xhr = new XMLHttpRequest();
        options.pre(xhr) && options.pre(xhr);
        makeCallback(xhr, options.callback);
        xhr.open('post', options.url);
        if (options.data instanceof FormData) {
    
     return xhr.send(options.data) };
        xhr.setRequestHeader(
            'Content-Type',
            'application/x-www-form-urlencoded'
        );
        this.xhr.send(
            typeof options.data == 'string' ? options.data : toQueryString(options.data)
        );
    }
    this.postJson = function (options) {
    
    
        options.data = options.data || '';
        var xhr = new XMLHttpRequest();
        options.pre(xhr) && options.pre(xhr);
        makeCallback(xhr, options.callback);
        xhr.open('post', options.url);
        if (options.data instanceof FormData) {
    
     return xhr.send(options.data) };
        xhr.setRequestHeader(
            'Content-Type',
            'application/json'
        );
        xhr.send(
            typeof options.data == 'string' ? options.data : JSON.stringify(options.data)
        );
    }
    this.post = this.postJson;
}

// ES6 版本
class Ajax {
    
    
    #toQueryString = function () {
    
    
        function recursive(value, key) {
    
    
            var queryStr = '';
            if (typeof value != 'object')
                queryStr += key + '=' + value + '&';
            else
                for (let item in value)
                    queryStr += key == undefined ? recursive(value[item], item) : recursive(value[item], key + '[\'' + item + '\']');
            return queryStr;
        }
        return function (value) {
    
    
            return recursive(value).slice(0, -1);
        }
    }();
    #makeCallback = function (xhr, callback) {
    
    
        xhr.onerror = function (err) {
    
    
            callback(err, undefined, xhr);
        };
        xhr.onload = function () {
    
    
            let contentType = xhr.getResponseHeader("Content-Type");
            callback(
                undefined,
                contentType && contentType.includes("application/json")
                    ? JSON.parse(xhr.responseText)
                    : xhr.responseText,
                xhr
            );
        };
    };

    get({
    
     url, data, callback, pre }) {
    
    
        data = data || '';
        const xhr = new XMLHttpRequest();
        pre && pre(xhr);
        this.#makeCallback(xhr, callback);
        xhr.open(
            "get",
            url + "?" + (typeof data == "string" ? data : this.#toQueryString(data))
        );
        xhr.send();
    }
    postUrl({
    
     url, data, callback, pre }) {
    
    
        data = data || '';
        const xhr = new XMLHttpRequest();
        pre && pre(xhr);
        this.#makeCallback(xhr, callback);
        xhr.open("post", url);
        if (data instanceof FormData) {
    
     return xhr.send(data) };
        xhr.setRequestHeader(
            "Content-Type",
            "application/x-www-form-urlencoded"
        );
        xhr.send(typeof data == "string" ? data : this.#toQueryString(data));
    }
    postJson({
    
     url, data, callback, pre }) {
    
    
        data = data || '';
        const xhr = new XMLHttpRequest();
        pre && pre(xhr);
        this.#makeCallback(xhr, callback);
        xhr.open("post", url);
        if (data instanceof FormData) {
    
     return xhr.send(data) };
        xhr.setRequestHeader("Content-Type", "application/json");
        xhr.send(typeof data == "string" ? data : JSON.stringify(data));
    }
    post({
    
     url, data, callback, pre }) {
    
    
        this.postJson({
    
     url, data, callback, pre });
    }
}

It can be found that when calling my interface, the data field passed in are all objects.
In fact, for the caller, allowing direct object transfer is a very friendly interface design.

Next up the jQuery interface:

// url
$.ajax(
    {
    
    
        type: 'get',

        url: 'http://example.com/route',

        data: {
    
     content: 'content' },

        contentType: 'application/x-www-form-urlencoded',// 可缺省

        beforeSend: function () {
    
    
            return false;
        },

        success: function (res) {
    
    
            res;
        },

        error: function (xhr) {
    
    

        }
    }
);
// json
$.ajax(
    {
    
    
        type: 'post',

        url: 'http://example.com/route',

        data: JSON.stringify({
    
     content: 'content' }),

        contentType: 'application/json',

        beforeSend: function () {
    
    
            return false;
        },

        success: function (res) {
    
    
            res;
        },

        error: function (xhr) {
    
    

        }
    }
);

When we need the post type to be application/json, ie json format data, we must call
JSON.stringify() to
wrap the object before passing it to the data field .

This is very unreasonable

First of all, the first point, this is the most incomprehensible place for me. As
we know, web apis only provides the stringify method from the object to the json string, but does not provide the interface from the object to the url querystring.
Then for urlencoded, the default submission method of the jQuery ajax interface, it also needs to encapsulate an additional object to querystring method, and then internally convert the object to querystring for us.
However, it does not convert the json format that provides the interface.

Some people may think that object to querystring is a very simple thing, but a loop, but it is not.
json is a tree structure. In other words, we need to traverse the tree and use obj[node].obj1[node1] string representation for each node.
Due to my algorithm based comparison, I wrote that it was two o’clock in the morning that day, Finally realized with recursion

function toQueryString () {
    
    
        function recursive(value, key) {
    
    
            var queryStr = '';
            if (typeof value != 'object')
                queryStr += key + '=' + value + '&';
            else
                for (let item in value)
                    queryStr += key == undefined ? recursive(value[item], item) : recursive(value[item], key + '[\'' + item + '\']');
            return queryStr;
        }
        return function (value) {
    
    
            return recursive(value).slice(0, -1);
        }
    }();

However, the specific implementation is not the point. The point is,
why jQuery takes great effort to encapsulate toQueryString for us, but refuses to call JSON.stringify() for our json?

Then there is the second point. The
jQuery interface can completely process the data field differently by judging the contentType field parameters. This is not a very troublesome thing, and it can even be said to be a convenient solution. Why doesn't he do this?

Guess you like

Origin blog.csdn.net/qq_16181837/article/details/105479520