Skip to content
On this page

xhr 请求 ​

xhr 请求源码难度不高,但是设计的比较巧妙,先定义一个柯里化的callback函数,做请求结束的处理函数,再通过callback()、callback('error')、callback('abort')的方式定义了各种状态处理,执行一次之后再置空销毁,保证 callback 函数只会执行一次

js
jQuery.ajaxSettings.xhr = function () {
  return new window.XMLHttpRequest();
};

var xhrSuccessStatus = {
  // File protocol always yields status code 0, assume 200
  0: 200
};

jQuery.ajaxTransport(function (options) {
  var callback;

  return {
    send: function (headers, complete) {
      var i,
        xhr = options.xhr();

      xhr.open(
        options.type,
        options.url,
        options.async,
        options.username,
        options.password
      );

      // Apply custom fields if provided
      if (options.xhrFields) {
        for (i in options.xhrFields) {
          xhr[i] = options.xhrFields[i];
        }
      }

      // Override mime type if needed
      if (options.mimeType && xhr.overrideMimeType) {
        xhr.overrideMimeType(options.mimeType);
      }

      if (!options.crossDomain && !headers['X-Requested-With']) {
        headers['X-Requested-With'] = 'XMLHttpRequest';
      }

      // Set headers
      for (i in headers) {
        xhr.setRequestHeader(i, headers[i]);
      }

      // Callback
      callback = function (type) {
        return function () {
          if (callback) {
            callback =
              xhr.onload =
              xhr.onerror =
              xhr.onabort =
              xhr.ontimeout =
                null;

            if (type === 'abort') {
              xhr.abort();
            } else if (type === 'error') {
              complete(xhr.status, xhr.statusText);
            } else {
              complete(
                xhrSuccessStatus[xhr.status] || xhr.status,
                xhr.statusText,

                (xhr.responseType || 'text') === 'text'
                  ? { text: xhr.responseText }
                  : { binary: xhr.response },
                xhr.getAllResponseHeaders()
              );
            }
          }
        };
      };

      // Listen to events
      xhr.onload = callback();
      xhr.onabort = xhr.onerror = xhr.ontimeout = callback('error');

      // Create the abort callback
      callback = callback('abort');

      try {
        // Do send the request (this may raise an exception)
        xhr.send((options.hasContent && options.data) || null);
      } catch (e) {
        // trac-14683: Only rethrow if this hasn't been notified as an error yet
        if (callback) {
          throw e;
        }
      }
    },

    abort: function () {
      if (callback) {
        callback();
      }
    }
  };
});