Isn’t the state of JavaScript development wonderful?
So I’m building this fairly robust little JavaScript workflow infrastructure. Within it, each hosted “step” can perform operations – and some of those operations may perform real persistence and need concurrency checks to ensure data integrity. So, let’s say a step has operations a, b and c, where b and c need the concurrency check. I wanted a clean way of opting into that check, but of course I didn’t want to add noise to each underlying operation – this is a cross-cutting concern which has effectively nothing to do with the actual operation.
In ES5, we’d just do this imperatively with a wrapper function like this:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| function verifyConcurrency(originalFunction) { | |
| return function () { | |
| return this.verifyConcurrency().then(function() { | |
| return originalFunction.apply(this, arguments); | |
| }); | |
| }; | |
| }; | |
| } |
..and then we’d use that higher order function to wrap our various opt-in methods:
var myObject = {
a: verifyConcurrency(a)
}
However with the lovely forthcoming ECMAScript decorator proposal, we can can apply this same pattern in a clearer manner using decorators:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| function verifyConcurrency() { | |
| return function (target, key, descriptor) { | |
| const originalFunction = descriptor.value; | |
| descriptor.value = async function () { | |
| await this.verifyConcurrency(); | |
| return originalFunction.apply(this, arguments); | |
| }; | |
| return descriptor; | |
| }; | |
| } |
And then the target function need only be decorated (adding very little noise):
class Myclass {
@verifyConcurrency()
async a(){
...
}
}
This is very easy to set up in your project:
- npm install babel-plugin-transform-decorators-legacy and add it to your babel pluggin configuration.
- Assuming you are linting, npm install babel-eslint and change your lint configuration to use babel’s eslint parser (as eslint doesn’t-yet support this experimental language feature).
Now you can use the decorator syntax and enjoy the improved code clarity 🙂