How To Synchronously Call A Set Of Functions In Javascript
Solution 1:
Use promises:
//The set of functions that I want to call in orderfunctiongetData(initialData) {
//gets the datareturnnewPromise(function (resolve, reject) {
resolve('Hello World!')
})
}
functionparseData(dataFromGetDataFunction) {
//does some stuff with the datareturnnewPromise(function (resolve, reject) {
resolve('Hello World!')
})
}
functionvalidate(dataFromParseDataFunction) {
//validates the datareturnnewPromise(function (resolve, reject) {
resolve('Hello World!')
})
}
//The function that orchestrates these calls functionrunner(initialData) {
returngetData(initialData)
.then(parseData)
.then(validate)
}
runner('Hello World!').then(function (dataFromValidateFunction) {
console.log(dataFromValidateFunction);
})
Not only are they easy to grasp, it makes total sense from a code readability stand point. Read more about them here. If you are in a browser environment, I recommend this polyfill.
Solution 2:
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 datacallback(/*...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:
functiongetData(callback) {
returnnewPromise(function(resolve, reject) {
someAsyncOperation(function() {
// Async is done now, call the callback with the dataresolve(/*...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";
functiongetData() {
// Return a promisereturnnewPromise((resolve, reject) => {
setTimeout(() => {
// Let's fail a third of the timeif (Math.random() < 0.33) {
reject("getData failed");
} else {
resolve('{"msg":"This is the message"}');
}
}, Math.random() * 100);
});
}
functionparseData(data) {
// Note that this function is synchronousreturnJSON.parse(data);
}
functionvalidate(data) {
// Let's assume validation is synchronous too// Let's also assume it fails half the timeif (!data || !data.msg || Math.random() < 0.5) {
thrownewError("validation failed");
}
// It's finereturn data;
}
functionrunner() {
returngetData()
.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
);
<inputtype="button"id="the-button"value="Click to test">
(you can test more than once)
Solution 3:
You should change each function to return a Promise
, which will allow your final function to become:
function runner() {
return Promise.try(getData).then(parseData).then(validate);
}
To do that, the body of each function should be wrapped in a new promise, like:
functiongetData() {
returnnewPromise(function (res, rej) {
var req = newAjaxRequest(...); // make the request
req.onSuccess = function (data) {
res(data);
};
});
}
This is a very cursory example of how promises might work. For more reading, check out:
- 2ality's fantastic blog posts: part 1 and part 2
- bluebird's documentation on why promises
- mdn's documentation on JS'
Promise
class
Post a Comment for "How To Synchronously Call A Set Of Functions In Javascript"