没有jQuery的Vanilla Ajax指南

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

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

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

在这里,我们正在创建必需类的实例,以向服务器发出HTTP请求。 然后,我们调用其open方法,将HTTP请求方法指定为第一个参数,将我们请求的页面的URL指定为第二个参数。 最后,我们调用其send方法,将null作为参数传递。 如果发布请求(此处使用GET),则此参数应包含我们要与请求一起发送的任何数据。

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

xhr.onreadystatechange = function () {
  var DONE = 4; // readyState 4 means the request is done.
  var OK = 200; // status 200 is a successful return.
  if (xhr.readyState === DONE) {
    if (xhr.status === OK) {
      console.log(xhr.responseText); // 'This is the returned text.'
    } else {
      console.log('Error: ' + 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(function(err) {
  console.log('Error: ' + err.status);
});

很好 对于包括您在内的许多人来说,确实如此,当涉及到Ajax时,jQuery已成为事实上的标准。 但是,你知道吗? 不一定是这种情况。 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) {
    render(req.url.slice(1), 'application/javascript', httpHandler);
  } else if (req.headers['x-requested-with'] === 'XMLHttpRequest') {
    // Send Ajax response
  } else {
    render('views/index.html', 'text/html', httpHandler);
  }
});

这将检查请求URL,以确定应用程序应如何响应。 如果请求来自scripts目录,那么将使用application/javascript的内容类型来提供适当的文件。 否则,如果请求的x-requested-with标头已设置为XMLHttpRequest那么我们知道我们正在处理Ajax请求,并且可以适当地响应。 并且如果都不是这种情况,则将提供views/index.html文件。

在我们深入研究服务器的Ajax响应时,我将扩展注释掉的部分。 在Node.js中,我不得不对renderhttpHandler做一些繁重的httpHandler

// app.js
function render(path, contentType, fn) {
  fs.readFile(__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('An error has occured: ' + err.message);
  } else {
    res.writeHead(200, {'Content-Type': contentType});
    res.end(str);
  }
};

render函数异步读取请求文件的内容。 它传递了对httpHandler函数的引用,然后将其作为回调执行。 httpHandler函数检查是否存在错误对象(例如,如果无法打开请求的文件,则该错误对象将存在)。 提供一切都很好,然后使用适当的HTTP状态代码和内容类型为文件的内容提供服务。

测试API

像使用任何声音后端API一样,让我们​​编写一些单元测试以确保其正常工作。 对于这些测试,我呼吁超级测试和摩卡咖啡寻求帮助:

// test/app.request.js
it('responds with html', function (done) {
  request(app)
    .get('/')
    .expect('Content-Type', /html/)
    .expect(200, done);
});
it('responds with javascript', function (done) {
  request(app)
    .get('/scripts/index.js')
    .expect('Content-Type', /javascript/)
    .expect(200, done);
});
it('responds with json', function (done) {
  request(app)
    .get('/')
    .set('X-Requested-With', 'XMLHttpRequest')
    .expect('Content-Type', /json/)
    .expect(200, done);
});

这些可以确保我们的应用以正确的内容类型和HTTP状态代码响应不同的请求。 一旦安装了依赖项,就可以使用npm test从命令运行这些npm test

介面

现在,让我们看一下我们正在用HTML构建的用户界面:

// views/index.html
<h1>Vanilla Ajax without jQuery</h1>
<button id="retrieve" data-url="/">Retrieve</button>
<p id="results"></p>

HTML看起来很简洁。 如您所见,所有激动都发生在JavaScript中。

onreadystate与onload

如果您读过任何经典的Ajax书籍,那么到处都有onreadystate 。 该回调函数带有嵌套的ifs和大量的绒毛,使您难以记住自己的头部。 让我们将onreadystateonload事件放在一起。

(function () {
  var retrieve = document.getElementById('retrieve'),
    results = document.getElementById('results'),
    toReadyStateDescription = function (state) {
      switch (state) {
      case 0:
        return 'UNSENT';
      case 1:
        return 'OPENED';
      case 2:
        return 'HEADERS_RECEIVED';
      case 3:
        return 'LOADING';
      case 4:
        return 'DONE';
      default:
        return '';
      }
    };
  retrieve.addEventListener('click', function (e) {
    var oReq = new 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与onload生成的控制台输出的屏幕截图

onreadystate事件在各处触发。 它在每个请求的开始,结束时触发,有时只是因为它真的喜欢被触发。 但是根据规范, onload事件仅在请求成功时才触发。 因此, onload事件是一种现代API,您可以在几秒钟内充分利用它。 onreadystate事件是向后兼容的。 但是, onload事件应该是您选择的工具。 onload事件看起来像jQuery上的success回调,不是吗?

现在是时候将5磅重的哑铃放在一边,然后继续弯曲手臂。

设置请求头

jQuery在后台设置了请求标头,因此您的后端技术知道这是Ajax请求。 通常,只要发送适当的响应,后端就不在乎GET请求来自何处。 当您想使用相同的Web API支持Ajax和HTML时,这非常方便。 因此,让我们看一下如何在香草Ajax中设置请求标头:

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

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

if (req.headers['x-requested-with'] === 'XMLHttpRequest') {
  res.writeHead(200, {'Content-Type': 'application/json'});
  res.end(JSON.stringify({message: 'Hello World!'}));
}

如您所见,vanilla Ajax是一种灵活而现代的前端API。 您可以使用大量的请求标头,其中之一就是版本控制。 例如,假设我要支持此Web API的多个版本。 当我不想破坏URL而是提供一种机制,使客户端可以选择所需的版本时,这很有用。 我们可以这样设置请求标头:

oReq.setRequestHeader('x-vanillaAjaxWithoutjQuery-version', '1.0');

在后端,请尝试:

if (req.headers['x-requested-with'] === 'XMLHttpRequest' &&
    req.headers['x-vanillaajaxwithoutjquery-version'] === '1.0') {
  // Send Ajax response
}

Node.js为您提供了一个headers对象,可用于检查请求标头。 唯一的技巧是它以小写形式读取它们。

我们到家了,还没有流汗! 您可能想知道,关于Ajax还有什么要了解的? 好吧,有几个巧妙的技巧。

回应类型

您可能想知道,当我使用的是普通的旧JSON时,为什么responseText包含服务器响应。 原来是因为我没有设置正确的reponseType 。 这个Ajax属性非常适合告诉前端API服务器期望什么类型的响应。 因此,让我们充分利用它:

var oReq = new XMLHttpRequest();
oReq.onload = function (e) {
    results.innerHTML = e.target.response.message;
};
oReq.open('GET', e.target.dataset.url, true);
oReq.responseType = 'json';
oReq.send();

令人敬畏的是,我可以告诉API期望什么,而不必发送回然后我必须将其解析为JSON的纯文本。 几乎所有最新的主要浏览器都提供此功能。 jQuery当然会自动进行这种类型的转换。 但是,现在有了一种在普通JavaScript中执行相同操作的便捷方法,这不是很好吗? Vanilla Ajax支持许多其他响应类型,包括XML。

可悲的是,在Internet Explorer中,这个故事并不那么出色。 从IE 11开始,该团队尚未添加对xhr.responseType ='json'的支持 。 此功能将在Microsoft Edge上提供 。 但是,截至撰写本文时,该错误已将近两年未解决。 我的猜测是Microsoft的人们一直在努力改进浏览器。 我们希望Microsoft Edge(又名Project Spartan)能够兑现其诺言。

las,如果您必须解决此IE问题:

oReq.onload = function (e) {
    var xhr = e.target;
    if (xhr.responseType === 'json') {
        results.innerHTML = xhr.response.message;
    } else {
        results.innerHTML = JSON.parse(xhr.responseText).message;
    }
};

快取清除

人们往往会忘记的一种浏览器功能是缓存Ajax请求的功能。 例如,Internet Explorer默认情况下会执行此操作。 我曾经费时数小时试图弄清楚为什么我的Ajax不能正常工作。 幸运的是,jQuery默认会破坏浏览器缓存。 好吧,您也可以使用纯Ajax,这非常简单:

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

根据jQuery文档 ,它所做的就是将时间戳查询字符串附加到请求的末尾。 这使请求有些独特,并破坏了浏览器缓存。 您可以看到在触发HTTP Ajax请求时的样子:

控制台输出显示正在执行的缓存清除

多田! 全部没有戏剧。

结论

我希望您喜欢300lb卧推香草Ajax。 曾几何时,阿贾克斯是一只可怕的野兽,但仅此而已。 实际上,我们已经涵盖了Ajax的所有基础知识,而没有jQuery的cru脚,hem锁。

我将以简洁的方式向您发出Ajax调用:

var oReq = new XMLHttpRequest();
oReq.onload = function (e) {
    results.innerHTML = e.target.response.message;
};
oReq.open('GET', e.target.dataset.url + '?' + new Date().getTime(), true);
oReq.responseType = 'json';
oReq.send();

这是响应的样子:

Ajax响应的屏幕截图

别忘了,您可以在GitHub上找到整个演示。 我很乐意在评论中听到您在使用和不使用jQuery时的想法。

From: https://www.sitepoint.com/guide-vanilla-ajax-without-jquery/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值