jQuery 的 Ajax 模块在早期版本中几乎是每个前端项目的必备依赖,很多开发者每天都在使用 load()、$.get()、$.post() 这类便捷方法,却很少思考它们与 $.ajax() 究竟是什么关系。表面上看,这些方法各自独立,参数形态也不同,似乎只是 jQuery 提供的几个平行 API。但实际上,它们存在清晰的层次结构:load() 是一个补充了 DOM 操作能力的封装,$.get() 和 $.post() 则是 $.ajax() 的快捷入口。理解这层关系,不仅有助于排查请求异常,也能在阅读源码时快速定位问题。

一、快速认识四个方法的基础用法
在深入源码之前,先确认这四个方法各自的基本形态。load() 是 jQuery 对象上的实例方法,它把请求回来的 HTML 片段直接插入到匹配的元素内部。比如给某个 <div> 加载一个列表页的局部内容,可以这样写:
$('#listContainer').load('partial.html');
如果只想取回响应中的某一部分,可以在 URL 后面追加空格和选择器,jQuery 会从返回的 HTML 中筛出对应的节点再填充到目标元素里:
$('#listContainer').load('partial.html .item-list');
$.get() 和 $.post() 是全局函数,分别对应 GET 和 POST 两种请求方式。它们在调用时不需要关心 type 字段,也不需要手动处理 $.ajax() 那一长串配置项。下面是一个典型的 $.get() 请求:
$.get('https://api.ippipp.com/users', { page: 1 }, function (data) {
console.log(data);
}, 'json');
而 $.ajax() 则是功能最完整的底层方法,所有请求细节都通过一个配置对象传入,请求方式、数据类型、超时时间、跨域设置等都可以在这一层控制:
$.ajax({
url: 'https://api.ippipp.com/users',
method: 'GET',
data: { page: 1 },
dataType: 'json',
success: function (data) {
console.log(data);
}
});
二、从源码看四个方法的调用链
在 jQuery 源码中,$.get() 和 $.post() 的定义极其简短,它们本质上是 $.ajax() 的预设参数的包装器。以 jQuery 3.x 源码为例,其实现大致如下:
jQuery.each(["get", "post"], function (i, method) {
jQuery[method] = function (url, data, callback, type) {
if (jQuery.isFunction(data)) {
type = type || callback;
callback = data;
data = undefined;
}
return jQuery.ajax({
url: url,
type: method,
dataType: type,
data: data,
success: callback
});
};
});
这段代码清晰地说明了三个关键信息:第一,$.get() 和 $.post() 内部直接调用 $.ajax(),并把请求方式写死在 type 字段中;第二,它们允许省略 data 参数,直接传入回调函数;第三,type 参数最终被映射为 dataType,这也就是为什么在 $.get() 中传第四个参数能指定响应格式的原因。
接下来看 load() 的定义。它在 jQuery 对象原型上,底层同样调用了 $.ajax(),但做了一层额外的预处理。简化后的逻辑如下:
jQuery.fn.load = function (url, params, callback) {
var selector = "";
var parts = url.split(/\s+/);
if (parts.length > 1) {
url = parts[0];
selector = parts[1];
}
if (jQuery.isFunction(params)) {
callback = params;
params = undefined;
}
return this.each(function () {
var self = this;
jQuery.ajax({
url: url,
type: params ? "POST" : "GET",
dataType: "html",
data: params,
complete: function (res) {
var html = res.responseText;
if (selector) {
var container = document.createElement("div");
container.innerHTML = html;
jQuery(container).find(selector).appendTo(self);
} else {
jQuery(self).html(html);
}
if (callback) {
callback.call(self, res.responseText, res.statusText);
}
}
});
});
};
通过这段代码可以看到,load() 之所以能直接往元素里填内容,并不存在什么独立的底层实现,它无非是把 $.ajax() 返回的响应文本存入 responseText,再由自身的 complete 回调处理 DOM 写入。区别在于,$.get() 和 $.post() 把 success 作为用户回调,而 load() 则把用户回调挂在 complete 上。这意味着 load() 的回调无论是请求成功还是失败都会执行,而 $.get() 的 success 只在响应成功时触发。
三、关键差异:load() 与 get()/post() 的设计异同
将 load() 和其他两个快捷方法对比,最明显的差异就是它返回的是一个 jQuery 对象,而不是 XMLHttpRequest 对象。这导致 load() 无法链式调用 .done()、.fail() 等 Promise 风格的方法,因为前者返回的是被遍历的 DOM 集合。如果需要获取请求状态,只能通过回调参数来感知。而 $.get()、$.post()、$.ajax() 返回的都是 XMLHttpRequest 对象,在 jQuery 1.5 之后还实现了 Promise 接口,可以这样使用:
var request = $.get('https://api.ippipp.com/users');
request.done(function (data) {
// 处理数据
}).fail(function () {
// 处理错误
});
另一个容易忽略的差异是请求方式的选择逻辑。$.get() 强制使用 GET,$.post() 强制使用 POST,而 load() 会根据是否传入 params 来自动决定请求方式:传了参数就发 POST,不传就发 GET。这个设计在早期的服务端框架中很常见,因为 GET 请求的查询参数会拼在 URL 中,而 POST 的数据放在请求体内部,当数据量较大时更适合用 POST。
此外,load() 默认把 dataType 设置为 html,这意味着 jQuery 会以纯文本方式处理响应内容,不进行 JSON 解析。如果想要获取 JSON 数据,就应该选择 $.get() 或 $.ajax(),而不是用 load() 去加载接口。这种默认值区别本质上反映的是各自的使用场景:load() 面向页面片段复用,$.get() 和 $.post() 面向通用的数据请求。
四、参数映射规则与优先级
对于 $.get(),它的参数签名是 $.get(url [, data] [, success] [, dataType])。在实现中,jQuery 会对参数做动态适配:如果第二个参数是函数,那它会被当作 success 回调来处理。这种重载逻辑在源码中非常典型:
if (jQuery.isFunction(data)) {
type = type || callback;
callback = data;
data = undefined;
}
当用户写下 $.get('api.php', function(){}) 时,jQuery 会检测到 data 是一个函数,自动将它赋值给 callback,同时把 data 置为 undefined。这个处理方式可以追溯到 jQuery 1.0 版本,经历了多个版本迭代仍然保留,足以说明它设计的合理性与兼容性。
对于 $.post(),它的参数映射规则与 $.get() 完全一致,唯一的区别是 type 字段被固定为 POST。因此,这两个方法在源码中常常共用一段循环定义代码,可以减少重复,也便于维护。再看看 load() 的参数处理,它的第二个参数如果是一个函数,同样会被识别为回调,只是这个回调的签名是 function(responseText, statusText, xhr),不像 $.get() 的回调签名是 function(data, statusText, xhr) 这样直接拿到解析后的数据。
五、返回对象的类型差异
从调用返回值的角度来梳理,能更直观地区分这四个方法。在 jQuery 的源码中,$.ajax() 返回的是 jqXHR 对象,它是原生 XMLHttpRequest 的超集。而 $.get() 和 $.post() 的返回值就是 $.ajax() 的返回值,没有做任何包装,因此它们支持链式绑定事件处理器:
$.post('save.php', { id: 1 })
.done(function () {
console.log('保存成功');
})
.fail(function () {
console.log('保存失败');
});
load() 则是一个例外,它返回的是当前匹配的 jQuery 对象。在源码中,它通过 this.each(function(){}) 遍历匹配的元素,并在每次循环中发起一个 Ajax 请求。这意味着如果用 load() 选中了三个元素,jQuery 会同时发出三个请求,每个请求返回的内容分别填充到对应的元素中。如果滥用这个特性,可能会给服务端带来额外的并发压力。
从事件回调的执行顺序来看,load() 内部使用的是 complete 回调而不是 success。在 jQuery 的请求流程中,success 只在状态码为 2xx 时触发,而 complete 无论请求是否成功都会执行。因此,在 load() 的回调中检查 statusText 或 res.status 才能准确判断请求结果:
$('#box').load('content.html', function (responseText, statusText, xhr) {
if (statusText === 'success') {
// 请求成功
} else {
// 请求失败
}
});
六、完整的调用链路梳理
将上述分析归纳成一条调用链,可以直观地看到:$.get() 和 $.post() 只是 $.ajax() 的语法糖,它们短小精悍,省去了写 type 字段和 success 配置的步骤。而 load() 在调用链上多走了一步:它先解析 URL 中的选择器部分,再决定提交方式,最后在 complete 中对响应文本做 DOM 注入。整个过程可以抽象为下面的流程图来理解。
从设计哲学来看,jQuery 把这些方法放在不同层级是经过深思熟虑的。$.ajax() 提供了最完整的控制力,适合处理复杂的请求场景,比如需要自定义请求头、设置超时时间、禁用缓存、指定 context 等高级配置;$.get() 和 $.post() 则面向大多数常规请求,牺牲了一部分灵活性换来了调用简洁;load() 更进一步缩小了适用范围,专门解决局部刷新问题。
为了验证这个调用链,可以通过在 $.ajax() 上挂一个自定义监听器来观察调用过程。在下面这段代码中,重写了 $.ajax(),并在里面打印日志,然后再调用 $.get(),可以看到日志确实输出了:
var originalAjax = jQuery.ajax;
jQuery.ajax = function (options) {
console.log('$.ajax() 被调用,请求方式:' + options.type);
return originalAjax(options);
};
$.get('https://api.ippipp.com/users', function () {
console.log('请求完成');
});
同理,调用 load() 时,也会经过这个重写后的 $.ajax(),打印出日志。通过这个实验可以验证,无论哪一个快捷方法,最终都汇聚到 $.ajax() 的同一个入口。而在 jQuery 源码内部,$.ajax() 又会经过 ajaxSetup、ajaxPrefilter、ajaxTransport 等多个预处理环节,最终才交给浏览器发送真实的网络请求。
七、开发实践中的选型建议
把四个方法放进具体的项目场景中,选择起来会变得很简单。如果页面中有一个固定的容器需要加载服务端返回的 HTML 片段,优先考虑 load(),因为它省去了手动把响应插入 DOM 的步骤。如果是从接口获取 JSON 数据并做复杂的渲染逻辑,用 $.get() 或 $.post() 更合适,因为可以链式使用 .done() 和 .fail() 处理异步流程。
如果请求需要携带自定义请求头,比如 Authorization、X-CSRF-Token,或者需要监听上传进度、设置超时,那就应该直接使用 $.ajax()。在这些需求下,快捷方法反而会因为隐式配置而导致排查困难。例如,$.get() 默认的 contentType 是 application/x-www-form-urlencoded; charset=UTF-8,但 $.ajax() 可以通过配置 contentType 字段自由切换为 application/json。
需要注意的是,在 jQuery 3.0 之后,$.ajax() 返回的 jqXHR 对象已经不再支持 success、error、complete 这些回调选项的链式调用,它们被统一到 Promise 的 done、fail、always 方法中。因此新项目中,不建议再在 $.ajax() 配置里同时使用 success 和 done(),那样会导致回调执行两次,引发难以察觉的 bug。
最后再回到源码层面做一个小结:load() 的底层逻辑是 $.ajax() + HTML 注入补充,$.get() 是 $.ajax() 的 GET 快捷方式,$.post() 是 $.ajax() 的 POST 快捷方式。理解了这条清晰的层级关系,在阅读任何基于 jQuery 封装的前端代码时都能快速判断某个请求的真实行为,也有助于在必要的时候剥离 jQuery,用原生 fetch 或 XMLHttpRequest 写出等价的逻辑。