资讯专栏INFORMATION COLUMN

jquery ajax 方法封装说明

z2xy / 3023人阅读

摘要:简要说明前面我写了一篇方法封装及文件设计文档,主要用来说明我们在项目中通常会对的方法进行进一步的封装处理,便于我们在业务代码中使用。这篇文档我们主要对封装的方法进行一个简要说明。

简要说明

前面我写了一篇《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");
  });

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

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

实际上,从 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);
    }
  });

既然已经可以使用这种方式使用 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;

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/103025.html

相关文章

  • Ajax设置请求和接收响应、自己封装简易jQuery.Ajax、回调函数

    摘要:设置请求和接收响应自己封装简易这篇文章是承接前几篇博客的是前几篇继续学习包括学习与理解和简化版自己实现等这篇文章只算是我的个人学习笔记内容没有精心排版一些错误请见谅所有代码都在这里从历史可以看到所有代码摆阔一个简易的服务器所有代码在历史里 Ajax设置请求和接收响应、自己封装简易jQuery.Ajax 这篇文章是承接前几篇博客的,是前几篇继续学习包括Ajax学习与理解和简化版自己实现j...

    Harpsichord1207 评论0 收藏0
  • 前后分离模型之封装 Api 调用

    摘要:和异步处理调用访问数据采用的方式,这是一个异步过程,异步过程最基本的处理方式是事件或回调,其实这两种处理方式实现原理差不多,都需要在调用异步过程的时候传入一个在异步过程结束的时候调用的接口。 Ajax 和异步处理 调用 API 访问数据采用的 Ajax 方式,这是一个异步过程,异步过程最基本的处理方式是事件或回调,其实这两种处理方式实现原理差不多,都需要在调用异步过程的时候传入一个在异...

    trilever 评论0 收藏0
  • 异步 JavaScript 与 Promise

    摘要:为这些回调函数分别命名并分离存放可以在形式上减少嵌套,使代码清晰,但仍然不能解决问题。如果在一个结束成功或失败,同前面的说明后,添加针对成功或失败的回调,则回调函数会立即执行。 异步? 我在很多地方都看到过异步(Asynchronous)这个词,但在我还不是很理解这个概念的时候,却发现自己常常会被当做已经很清楚(* ̄ロ ̄)。 如果你也有类似的情况,没关系,搜索一下这个词,就可以得到大致...

    livem 评论0 收藏0
  • jQuery笔记总结篇

    摘要:希望在做所有事情之前,操作文档。不受层级限制子选择器在给定的父元素下匹配所有子元素。相邻选择器匹配所有紧接在元素后的元素。判断当前对象中的某个元素是否包含指定类名,包含返回,不包含返回下标过滤器精确选出指定下标元素获取第个元素。 原文链接 http://blog.poetries.top/2016... 首先,来了解一下jQuery学习的整体思路 showImg(https://seg...

    NoraXie 评论0 收藏0
  • Jquery就是这么简单

    摘要:在内部还是调用这些方法。对象下标,从开始对象下标,从开始再次重申对象只能调用对象的,对象只能调用对象的对象转成值得注意的是在脚本内,是代表对象的。对象转成对象语法也非常简单在内写上对象,就变成了对象了。在文档中对它的解释是这样子的。 什么是Jquery? Jquey就是一款跨主流浏览器的JavaScript库,简化JavaScript对HTML操作 就是封装了JavaScript,能够...

    wpw 评论0 收藏0

发表评论

0条评论

z2xy

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<