on
Italy
- Get link
- X
- Other Apps
var xhr = new XMLHttpRequest();
xhr.open('GET', 'send-ajax-data.php');
xhr.send(null);
open
method, specifying the HTTP request method as the first parameter and
the URL of the page we’re requesting as the second. Finally, we call its
send method passing null as a parameter. If POST-ing the
request (here we are using GET), this parameter should contain any data
we want to send with the request.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.
}
}
};
The onreadystatechange is asynchronous, which means it
gets called at any time. These types of functions are callbacks — one
that gets called once some processing finishes. In this case, the
processing is happening on the server.$.ajax({
url: 'send-ajax-data.php',
})
.done(function(res) {
console.log(res);
})
.fail(function(err) {
console.log('Error: ' + err.status);
});
Which is nice. And indeed for many, including yours truly, jQuery has
become the de facto standard when it comes to Ajax. But, do you know
what? This doesn’t have to be the case. jQuery exists to get around the
ugly DOM API. But, is it really that ugly? Or incomprehensible? // 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);
}
});
scripts directory, then the appropriate file is served with the content type of application/javascript. Otherwise, if the request’s x-requested-with headers have been set to XMLHttpRequest
then we know we’re dealing with an Ajax request and we can respond
appropriately. And if neither of these is the case, the file views/index.html is served.render and 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);
}
};
The render function asynchronously reads the contents of the requested file. It is passed a reference to the httpHandler function, which it then executes as a callback. The httpHandler
function checks for the presence of an error object (which would be
present, for example, if the file requested could not be opened).
Providing everything is good, it then serves the contents of the file
with the appropriate HTTP status code and content type.// 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);
});
npm test.// views/index.html
Vanilla Ajax without jQuery
The HTML looks nice and neat. As you can see, all the excitement is happening in JavaScript.onreadystate
everywhere. This callback function comes complete with nested ifs and
lots of fluff that makes it difficult to remember off the top of your
head. Let’s put the onreadystate and onload events head to head.(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();
});
}());
This is the output in the console:onreadystate event fires all over the
place. It fires at the beginning of each request, at the end, and
sometimes just because it really likes getting fired. But according to
the spec, the onload event fires only when the request succeeds. So, the onload event is a modern API you can put to good use in seconds. The onreadystate event is there to be backwards compatible. But, the onload event should be your tool of choice. The onload event looks like the success callback on jQuery, does it not?var oReq = new XMLHttpRequest();
oReq.open('GET', e.target.dataset.url, true);
oReq.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
oReq.send();
With this, we can do a check in Node.js:if (req.headers['x-requested-with'] === 'XMLHttpRequest') {
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify({message: 'Hello World!'}));
}
oReq.setRequestHeader('x-vanillaAjaxWithoutjQuery-version', '1.0');
And in the back-end, try:if (req.headers['x-requested-with'] === 'XMLHttpRequest' &&
req.headers['x-vanillaajaxwithoutjquery-version'] === '1.0') {
// Send Ajax response
}
Node.js gives you a headers object you can use to check for request headers. The only trick is it reads them in lowercase.responseText contains the server response when all I’m working with is plain old JSON. Turns out, it is because I did not set the proper reponseType.
This Ajax attribute is great for telling the front-end API what type of
response to expect from the server. So, let’s put this to good use: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();
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;
}
};
var bustCache = '?' + new Date().getTime();
oReq.open('GET', e.target.dataset.url + bustCache, true);
Per the jQuery documentation,
all it does is append a timestamp query string to the end of the
request. This makes the request somewhat unique and busts the browser
cache. You can see what this looks like when you fire HTTP Ajax
requests: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();
Comments
Post a Comment