没有jQuery的香草Ajax指南

卡米洛·雷耶斯
分享

异步JavaScript和XML的简称,Ajax是一种进行部分页面更新的机制。它使您能够使用来自服务器的数据更新页面的各个部分,同时避免了完全刷新的需要。以这种方式进行部分更新可以有效地创建流畅的用户体验,并可以减少服务器上的负载。

这是一个基本Ajax请求的剖析:

var xhr = new XMLHttpRequest();xhr。开放('GET', 'send-ajax-data.php'); xhr.send(null);

在这里,我们正在创建所需类的实例,以便向服务器发出HTTP请求。我们称之为开放方法,将HTTP请求方法指定为第一个参数,将我们请求的页面的URL指定为第二个参数。最后,我们称其为发送方法将null作为参数传递。如果post请求(这里我们使用GET),这个参数应该包含我们想要随请求发送的任何数据。

这是我们如何处理来自服务器的响应:

xhr。onreadystatechange = function () {var DONE = 4;// readyState 4表示请求完成。var OK = 200;// status 200返回成功如果(xhr。readyState === DONE) {if (xhr。status === OK) {console.log(xhr.responseText);// '这是返回的文本'}其他{console.log('错误:' + xhr.status); // An error occurred during the request. } } };

onreadystatechange是异步的,这意味着它在任何时候都会被调用。这些类型的函数是回调函数——一旦某些处理完成就会被调用。在本例中,处理在服务器上进行。

对于那些希望更多地了解Ajax基础知识的人,MDN网络提供了好向导

使用jQuery还是不使用jQuery?

因此,好消息是上面的代码可以在所有最新的主要浏览器上运行。坏消息是,它相当复杂。讨厌的东西!我已经在渴望一个优雅的解决方案了。

使用jQuery,可以将整个代码片段压缩为:

美元。Ajax ({url: 'send-ajax-data.php',}) .done(function(res) {console.log(res);}) .fail(函数(err) {console.log('错误:' + err.status);});

这很好。事实上,对于很多人来说,jQuery已经成为Ajax的实际标准。但是,你知道吗?这并不一定是这样的。jQuery的存在是为了绕过丑陋的DOM API。但是,真的吗丑吗?还是无法理解?

在本文的剩余部分,我将研究在普通JavaScript中对Ajax API所做的改进。整个规范可以在W3C.这个规范让我印象深刻的是它的名字。它不再是“XMLHttpRequest Level 2”,而是“XMLHttpRequest Level 1”——这是2011年两个规范合并的结果。今后,从标准的角度来看,它将被视为一个单一的实体,生活水平将被称为生活水平XMLHttpRequest.这表明社区承诺坚持一个标准,这对那些想要摆脱jQuery的开发人员来说是好消息。

让我们开始吧……

设置

对于本文,我使用node . js在后端。是的,浏览器和服务器上将会有JavaScript。Node.js的后端是精简的,我鼓励你下载整个演示GitHub跟着我走。以下是服务器上的主要内容:

// app.js var app = http。createServer(function (req, res) {if (req.url. indexof ('/scripts/') >= 0){渲染(req.url.slice(1), '应用程序/javascript', httpHandler);} else if (req。头['x-requested-with'] === 'XMLHttpRequest') { // Send Ajax response } else { render('views/index.html', 'text/html', httpHandler); } });

这将检查请求URL,以确定应用程序应该如何响应。如果请求来自脚本目录,则提供内容类型为的适当文件应用程序/ javascript.否则,如果请求为x-requested-with头文件已设置为XMLHttpRequest那么我们就知道我们正在处理一个Ajax请求,我们可以做出适当的响应。如果这两种情况都不是,那文件视图/ index . html是服务。

在深入讨论来自服务器的Ajax响应时,我将展开被注释掉的部分。在Node.js中,我必须对渲染而且httpHandler

// app.js函数渲染(path, contentType, fn) {fs. jsreadFile(__dirname + '/' + path, 'utf-8', function (err, str) {fn(err, str, contentType);});} var httpHandler = function (err, str, contentType) {if (err) {res.writeHead(500, {'Content-Type': 'text/plain'});res.end('一个错误已经发生:' + err.message);} else {res.writeHead(200, {'Content-Type': contentType});res.end (str);}};

渲染函数异步读取所请求文件的内容。对象的引用传递给httpHandler函数,然后作为回调函数执行。的httpHandler函数检查是否存在错误对象(例如,如果请求的文件无法打开,则会出现错误对象)。如果一切正常,它将使用适当的HTTP状态代码和内容类型提供文件的内容。

测试API

与任何合理的后端API一样,让我们编写一些单元测试来确保它能够工作。为了这些测试,我要求supertest而且摩卡寻求帮助:

// test/app.request.js it('响应html',函数(完成){request(app) .get('/') .expect('Content-Type', /html/) .expect(200,完成);});it('用javascript响应',function (done) {request(app) .get('/scripts/index.js') .expect('Content-Type', /javascript/) .expect(200, done);});it(' response with json', function (done) {request(app) .get('/') .set('X-Requested-With', 'XMLHttpRequest') .expect('Content-Type', /json/) .expect(200, done);});

这确保我们的应用程序以正确的内容类型和HTTP状态代码响应不同的请求。安装依赖项之后,可以使用命令运行这些测试npm测试

的接口

现在,让我们来看看我们在HTML中构建的用户界面:

/ /视图/ index . html<h1>没有jQuery的香草Ajaxh1><按钮id检索data-url/>检索按钮><pid结果>p>

HTML看起来很整洁。如您所见,所有令人兴奋的事情都发生在JavaScript中。

Onreadystate vs onload

如果您阅读任何有关Ajax的权威书籍,您可能会发现onreadystate无处不在。这个回调函数带有嵌套的if和大量的绒毛,这使得你很难立即记住它。让我们把onreadystate而且onload事件针锋相对。

(function () {var retrieve = document.getElementById('retrieve'), results = document.getElementById('results'), toReadyStateDescription = function (state) {switch (state) {case 0:返回'UNSENT';case 1:返回'OPENED';case 2:返回'HEADERS_RECEIVED';case 3:返回'LOADING';case 4:返回'DONE';默认值:返回";}};检索。addEventListener('点击',函数(e) {var oReq =新的XMLHttpRequest();oReq。onload = function () { console.log('Inside the onload event'); }; oReq.onreadystatechange = function () { console.log('Inside the onreadystatechange event with readyState: ' + toReadyStateDescription(oReq.readyState)); }; oReq.open('GET', e.target.dataset.url, true); oReq.send(); }); }());

这是控制台的输出:

onreadystate vs onload生成的控制台输出的截图"width=

onreadystate到处都是火灾。它在每个请求的开始和结束时触发,有时只是因为它真的喜欢被触发。但根据说明书,onload事件仅在请求时触发成功.所以,onloadevent是一个可以在几秒钟内充分利用的现代API。的onreadystate事件是向后兼容的。但是,onload事件应该是您选择的工具。的onload事件看起来像成功jQuery回调,不是吗?

是时候把5磅的哑铃放在一边,开始练习手臂弯曲了。

设置请求报头

jQuery在后台设置请求头,以便后端技术知道这是一个Ajax请求。通常,后端并不关心GET请求来自何处,只要它发送正确的响应即可。当你想用相同的web API支持Ajax和HTML时,这就很方便了。那么,让我们看看如何在普通Ajax中设置请求头:

var oReq = new XMLHttpRequest();oReq。开放('GET', e.target.dataset.url, true); oReq.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); oReq.send();

有了这个,我们可以在Node.js中进行检查:

如果(点播。头['x-requested-with'] === 'XMLHttpRequest') { res.writeHead(200, {'Content-Type': 'application/json'}); res.end(JSON.stringify({message: 'Hello World!'})); }

如您所见,普通Ajax是一种灵活而现代的前端API。有很多想法可以使用请求头,其中之一是版本控制。举个例子,假设我想支持多个版本的web API。当我不想破坏url,而是提供一种机制,让客户端可以选择他们想要的版本时,这很有用。我们可以像这样设置请求头:

oReq。setRequestHeader(“x-vanillaAjaxWithoutjQuery-version”、“1.0”);

在后端,尝试:

如果(点播。头['x-requested-with'] === 'XMLHttpRequest' && req.headers['x-vanillaajaxwithoutjquery-version'] === '1.0') { // Send Ajax response }

Node.js给你一个对象,可用于检查请求标头。唯一的技巧是用小写字母来读。

我们已经到了最后阶段,还没流汗呢!您可能想知道,关于Ajax还有什么需要了解的呢?来点小技巧吧。

响应类型

你可能想知道为什么响应结果字符串包含服务器响应时,我所使用的是普通的JSON。结果是,这是因为我没有设置适当的reponseType.这个Ajax属性非常适合告诉前端API期望从服务器得到什么类型的响应。所以,让我们好好利用这个:

var oReq = new XMLHttpRequest();oReq。Onload =函数(e){结果。innerHTML = e.target.response.message;};oReq。开放('GET', e.target.dataset.url, true); oReq.responseType = 'json'; oReq.send();

太棒了,而不是发送回纯文本,然后我必须解析成JSON,我可以告诉API期望什么。这个特性在几乎所有最新的主流浏览器中都可用。当然,jQuery会自动完成这种类型的转换。但是,现在我们有了一种在纯JavaScript中做同样事情的方便方法,这不是很棒吗?Vanilla Ajax支持许多其他响应类型,包括XML。

遗憾的是,在ie浏览器中,这个故事就没那么精彩了。截至IE 11,团队还没有添加支持xhr。responseType = ' json '.这一特性即将到来微软的优势.但是,在撰写本文时,这个漏洞已经存在了近两年。我猜微软的人一直在努力改进浏览器。希望微软Edge(又名Project Spartan)能兑现承诺。

唉,如果你必须要解决IE的问题:

oReq。Onload =函数(e) {var XHR = e.target;如果(xhr。responseType === 'json'){结果。innerHTML = xhr.response.message;} else{结果。innerHTML = JSON.parse(xhr.responseText).message;}};

缓存的地沟油

人们容易忘记的一个浏览器特性是缓存Ajax请求的功能。例如,Internet Explorer在默认情况下是这样做的。我曾经挣扎了几个小时试图弄清楚为什么我的Ajax不能工作因为这个。幸运的是,jQuery默认情况下会破坏浏览器缓存。好吧,你也可以在纯Ajax,它是相当直接的:

var bustCache = '?' + new Date().getTime();oReq。开放('GET', e.target.dataset.url + bustCache, true);

根据jQuery文档,它所做的只是在请求的末尾追加一个时间戳查询字符串。这使得请求在某种程度上是唯一的,并破坏了浏览器缓存。你可以看到当你触发HTTP Ajax请求时是什么样子的:

控制台输出显示正在进行缓存破坏"width=

大作。一切都没有戏剧性。

结论

我希望你喜欢300磅的香草阿贾克斯卧推。曾几何时,阿贾克斯是一只可怕的野兽,但现在不是了。事实上,我们已经介绍了Ajax的所有基础知识,没有jQuery的束缚。

我将留给您一种简洁的Ajax调用方法:

var oReq = new XMLHttpRequest();oReq。Onload =函数(e){结果。innerHTML = e.target.response.message;};oReq。开放('GET', e.target.dataset.url + '?' + new Date().getTime(), true); oReq.responseType = 'json'; oReq.send();

回复是这样的:

Ajax响应截图"width=

别忘了,你可以在上面找到完整的演示GitHub.我欢迎在评论中听到你对Ajax和不使用jQuery的看法。

Redux没有反应状态管理在香草JavaScript"></a>
         <div class= Redux没有反应状态管理在香草JavaScript 莫里茨克罗格
快速提示:用Vanilla JavaScript添加或删除CSS类"></a>
         <div class= 快速提示:用Vanilla JavaScript添加或删除CSS类 Yaphi伯哈努
用香草JavaScript创建一个音乐果酱站"></a>
         <div class= 用香草JavaScript创建一个音乐果酱站 麦尔斯英语
如何在香草JavaScript中实现平滑滚动"></a>
         <div class= 如何在香草JavaScript中实现平滑滚动 朱里奥曼拉德
Baidu