Home > Web Front-end > JS Tutorial > Introduction to jquery ajax method encapsulation (with examples)

Introduction to jquery ajax method encapsulation (with examples)

不言
Release: 2019-03-27 09:16:43
forward
2756 people have browsed it

本篇文章给大家带来的内容是关于jquery ajax 方法封装的介绍(附示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

简要说明

前面我写了一篇《jquery ajax 方法封装及 api 文件设计》文档,主要用来说明我们在项目中通常会对 jquery 的 ajax 方法进行进一步的封装处理,便于我们在业务代码中使用。从那篇文档中我们可以了解到如何封装ajax方法、如何设计 API 文件,以及如何在业务代码中调用 API 接口。

这篇文档我们主要对封装的 ajax 方法进行一个简要说明。这里的封装主要是将 $.ajax() 返回的 jqXHR 对象,通过调用 jQuery.Deferred() 方法创建成一个可链式调用的工具对象(其实 jqXHR 本身就是 Deferred 对象,本来就可以进行链式调用,后面会对此进行说明)。这样我们就可以使用下面这种形式进行链式调用:

// 链式调用
absService.getAbsListData(conditionObj)
  .done(function (result) {
    var data = ts.handleData(result);
    ts.render(data, columnChange);
  })
  .fail(function (err, jqXHR) {
    Util.hideLoading('#abs-all-container');
  });
Copy after login

同时,通过一些处理,也允许调用者使用如下形式进行调用:

// 传入成功回调、失败回调
absService.getAbsListData(conditionObj, function (result) {
    var data = ts.handleData(result);
    ts.render(data, columnChange);
  }, function (err, jqXHR) {
    Util.hideLoading('#abs-all-container');
  });
Copy after login

实际上,从 jQuery 1.5 开始,$.ajax() 返回的 jqXHR 对象就已经实现了 Promise 接口, 使它拥有了 Promise 的所有属性,方法和行为。也就是说 $.ajax() 返回的 jqXHR 对象本身就可以使用如下形式的调用:

$.ajax(options)
  .done(function (result, textStatus, jqXHR) {
    if (requestId === requestIdentifier[serviceName]) {
      ajaxRequest.ajax.handleResponse(result, $dfd, jqXHR, userOptions, serviceName, requestId);
      }
  })
  .fail(function (jqXHR, textStatus, errorThrown) {
    if (requestId === requestIdentifier[serviceName]) {
      //jqXHR.status
      $dfd.reject.apply(this, arguments);
      userOptions.error.apply(this, arguments);
    }
  });
Copy after login

既然已经可以使用这种方式使用 jqXHR对象,那为什么不直接将 jqXHR对象返回,然后在业务代码中直接使用 jqXHR.done() 和 jqXHR.fail() 方法呢?为什么还要进一步将其包装成一个新的 Deferred 对象呢?

答:是为了在成功和失败回调调用之前做一些统一的处理,比如对接口返回的数据进行判断、对返回的 JSON 字符串进行解析、在请求失败时输出方法名和错误信息等,我们把这些每次接口调用都会进行的操作进行统一处理,实现代码复用,这样业务代码中就只需要关注拿到数据后的处理逻辑即可。

这些统一进行的操作,我们放在 $.ajax().done() 和 $.ajax().fail() 方法中去执行,然后将 $.ajax() 返回的 jqXHR对象包装成新的 Deferred 对象,这样就可以在业务代码中通过链式调用做进一步的处理,比如刷新表格内容、更新页面动态等等。

代码解读

/**
 * 封装 jquery ajax 
 * 例如:
 * ajaxRequest.ajax.triggerService(
 *   'apiCommand', [命令数据] )
 *   .then(successCallback, failureCallback);
 * );
 */
var JSON2 = require('LibsDir/json2');
var URL = '../AjaxHandler.aspx?r=';

// 用来记录每次请求的唯一标识, 键值对形式, 形如:
// var requestIdentifier = {
//   SearchABSList: 'b80a3876-9bca-40d1-b2cd-0daa799591e7',
//   SetABSUserColumns: 'cafe3f01-2ee2-41f0-aeca-d630429f89f4',
// };
var requestIdentifier = {};

// 唯一标识生成方法
function generateGUID() {
  var d = new Date().getTime();
  if (typeof performance !== 'undefined' && typeof performance.now === 'function') {
    d += performance.now();
  }
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
    var r = (d + Math.random() * 16) % 16 | 0;
    d = Math.floor(d / 16);
    return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
  });
}


// 模块主体
var ajaxRequest = ajaxRequest || {};
(function ($) {
  if (!$) {
    throw 'jquery获取失败!';
  }

  ajaxRequest.json = JSON2;

  /**
   * 触发请求, 返回包装成 Deferred 对象的 jqXHR
   * @param    {object}    userOptions   参数对象(包含方法名、参数对象、成功回调、失败回调)
   * @param    {string}    serviceName   方法名
   * @param    {string}    requestId     请求的唯一标识
   * @returns  object
   */
  ajaxRequest.ajax = function (userOptions, serviceName, requestId) {
    userOptions = userOptions || {};

    // 将参数对象与ajax的默认项组成一个新的对象, 作为 jquery ajax 方法的配置项
    var options = $.extend({}, ajaxRequest.ajax.defaultOpts, userOptions);

    // 将 jquery ajax 方法默认的 success 回调和 error 回调置为 undefined
    // .done()方法取代了的过时的jqXHR.success()方法
    // .fail()方法取代了的过时的.error()方法
    options.success = undefined;
    options.error = undefined;

    // 将 jqXHR 包装成新的 Deferred 对象返回
    // jQuery.Deferred([beforeStart]) 一个工厂函数, 这个函数返回一个链式实用对象
    // beforeStart - 一个构造函数返回之前调用的函数
    return $.Deferred(function ($dfd) {
      $.ajax(options)
        .done(function (result, textStatus, jqXHR) {
          if (requestId === requestIdentifier[serviceName]) {
            // 比对请求id, 保证返回结果的正确性 (重复请求有可能会带来返回结果不可靠的问题)
            ajaxRequest.ajax.handleResponse(result, $dfd, jqXHR, userOptions, serviceName, requestId);
          }
        })
        .fail(function (jqXHR, textStatus, errorThrown) {
          if (requestId === requestIdentifier[serviceName]) {
            // jqXHR.status
            $dfd.reject.apply(this, arguments);
            userOptions.error.apply(this, arguments);
          }
        });
    });
  };

  $.extend(ajaxRequest.ajax, {
    // $.ajax() 的默认设置
    defaultOpts: {
      // url: '../AjaxSecureHandler.aspx,
      dataType: 'json',
      type: 'POST',
      contentType: 'application/x-www-form-urlencoded; charset=UTF-8'
    },

    // 在业务代码的回调执行之前, 做一些统一处理, 实现代码复用
    // $dfd.resolve() 和 $dfd.reject() 的执行, 会使得使用 .then()/.done() 中的回调方法得到执行
    // userOptions.success() 和 userOptions.error() 是调用用户以参数形式传入的成功回调函数和失败回调函数
    // 一般来说, 上述两种方式只会有一个真正起到作用, 这取决于用户调用的方式: 
    // 如果是使用 $.ajax().done().fail() 这种方式调用, 那么 $dfd.resolve()/$dfd.reject() 会起到作用
    // 此时 userOptions.success/userOptions.error 都是 undefined, 自然不会得到执行, 反之亦然
    handleResponse: function (result, $dfd, jqXHR, userOptions, serviceName, requestId) {
      if (!result) {
        $dfd && $dfd.reject(jqXHR, 'error response format!');
        userOptions.error(jqXHR, 'error response format!');
        return;
      }

      // 服务器已经错误
      if (result.ErrorCode != '200') {
        $dfd && $dfd.reject(jqXHR, result.ErrorMessage);
        userOptions.error(jqXHR, result);
        return;
      }

      if (result.Data) {
        // 将大于2^53的数字(16位以上)包裹双引号, 避免溢出
        var jsonStr = result.Data.replace(/(:\s*)(\d{16,})(\s*,|\s*})/g, '$1"$2"$3');
        var resultData = ajaxRequest.json.parse(jsonStr);

        // $dfd.resolve() 执行之后, 业务代码中的回调会执行, 即.then()/.done()方法会得到执行
        $dfd.resolve(resultData);
        // 如果是使用传统的传入成功回调函数的形式进行调用的, 那么在此处调用用户设定的成功回调
        userOptions.success && userOptions.success(resultData);
      } else {
        $dfd.resolve();
        userOptions.success && userOptions.success();
      }
    },

    /**
     * 构建请求参数对象
     * @param    {string}    serviceName   方法名
     * @param    {object}    input         传入的参数对象
     * @param    {function}  userSuccess   成功回调
     * @param    {function}  userError     失败回调
     * @param    {object}    ajaxParams    其他参数
     * @returns  object
     */
    buildServiceRequest: function (serviceName, input, userSuccess, userError, ajaxParams) {
      // 这里是根据后台要求构建的
      var requestData = {
        MethodAlias: serviceName, // 方法名
        Parameter: input // 传递的参数
      };

      var request = $.extend({}, ajaxParams, {
        // 这里要对传递的 JSON 字符串参数数据使用 escape 方法进行编码
        // 'data=' 是根据项目约定增加的,与 contentType 相对应
        data: 'data=' + escape(ajaxRequest.json.stringify(requestData)),
        success: userSuccess,
        error: function (jqXHR, textStatus, errorThrown) {
          // 这里是在请求出错的时候做一个统一处理, 输出方法名和错误对象
          console.log(serviceName, jqXHR);
          if (userError && (typeof userError === 'function')) {
            userError(jqXHR, textStatus, errorThrown);
          }
        }
      });

      return request;
    },

    // 构建参数对象, 生成唯一标识, 触发请求
    triggerService: function (serviceName, input, success, error, ajaxParams) {
      // 构建参数对象
      var request = ajaxRequest.ajax.buildServiceRequest(serviceName, input, success, error, ajaxParams);

      // 生成此次 ajax 请求唯一标识
      var requestId = requestIdentifier[serviceName] = generateGUID();
      request.url = URL + requestId;

      // 触发请求
      return ajaxRequest.ajax(request, serviceName, requestId);
    }
  });

})(jQuery);

module.exports = ajaxRequest;
Copy after login

本篇文章到这里就已经全部结束了,更多其他精彩内容可以关注PHP中文网的JavaScript视频教程栏目!

The above is the detailed content of Introduction to jquery ajax method encapsulation (with examples). For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:segmentfault.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template