The code you've quoted will run synchronously. JavaScript function calls are synchronous.
So I'm going to assume that getData
, parseData
, and/or validate
involve asynchronous operations (such as using ajax in a browser, or readFile
in NodeJS). If so, you basically have two options, both of which involve callbacks.
The first is to just have those functions accept callbacks they'll call when done, for instance:
function getData(callback) {
someAsyncOperation(function() {
// Async is done now, call the callback with the data
callback(/*...some data...*/);
});
}
you'd use that like this:
getData(function(data) {
// Got the data, do the next thing
});
The problem with callbacks is that they're hard to compose and have fairly brittle semantics. So promises were invented to give them better semantics. In ES2015 (aka "ES6") or with a decent promises library, that would look something like this:
function getData(callback) {
return someAsyncOperation();
}
or if someAsyncOperation
is not promise-enabled, then:
function getData(callback) {
return new Promise(function(resolve, reject) {
someAsyncOperation(function() {
// Async is done now, call the callback with the data
resolve(/*...some data...*/);
// Or if it failed, call `reject` instead
});
});
}
Doesn't seem to do much for you, but one of the key things is composability; your final function ends up looking like this:
function runner() {
return getData()
.then(parseData) // Yes, there really aren't () on parseData...
.then(validate); // ...or validate
}
usage:
runner()
.then(function(result) {
// It worked, use the result
})
.catch(function(error) {
// It failed
});
Here's an example; it will only work on a fairly recent browser that supports Promise
and ES2015 arrow functions, because I was lazy and wrote it with arrow functions and didn't include a Promise lib:
"use strict";
function getData() {
// Return a promise
return new Promise((resolve, reject) => {
setTimeout(() => {
// Let's fail a third of the time
if (Math.random() < 0.33) {
reject("getData failed");
} else {
resolve('{"msg":"This is the message"}');
}
}, Math.random() * 100);
});
}
function parseData(data) {
// Note that this function is synchronous
return JSON.parse(data);
}
function validate(data) {
// Let's assume validation is synchronous too
// Let's also assume it fails half the time
if (!data || !data.msg || Math.random() < 0.5) {
throw new Error("validation failed");
}
// It's fine
return data;
}
function runner() {
return getData()
.then(parseData)
.then(validate);
}
document.getElementById("the-button").addEventListener(
"click",
function() {
runner()
.then(data => {
console.log("All good! msg: " + data.msg);
})
.catch(error => {
console.error("Failed: ", error && error.message || error);
});
},
false
);
<input type="button" id="the-button" value="Click to test">
(you can test more than once)
[javascript] asynchronous functions series
– Lobectomy