Nodejs - Asynchronous File Operations with Try-Catch

Handle Situation When File Does Not Exist in Directory

Performing a file reading operation to check whether or not a file exists before operating might cause a race condition as stated in the Nodejs section on fs.stat:

“Using fs.stat() to check for the existence of a file before calling fs.open(), fs.readFile() or fs.writeFile() is not recommended. Instead, user code should open/read/write the file directly and handle the error raised if the file is not available.”

In order to make it safer when using an asynchronous file read operation, a try-catch block should always wrap the async file operation because it will allow one to handle the situation when a file is indeed non-existent.

Here is an example where the library ‘co’ and ‘fs-extra-promises’ are used to show safe operation with the try-catch block on async operations:

Generators and Try-catch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { statAsync } from 'fs-extra-promise';
import co from 'co';

co(function* fileCheck() {
yield co.wrap(function* () {
try {
//statAsync is the promise version of fs.stat
const fileExists = yield statAsync('a/path/that/does/not/exists');

//Check if is a file type of folder type
//Do stuff when the path does exist
//fileExists.isFile() || fileExists.isDirectory()
} catch (e) {

//Errors out here because the path stated does not exists

//Do stuff here where there is an error
///...
}
};
});

Nodejs - Quick Tips #7

Identify Streams Better when Logging Two or More Streams at a Time

Rxjs provides a means of performing a ‘side effect’ without modifying the observable through the observable chain. The ‘do’ command is good candidate for use when there is a need to log out information when specific operations are performed.

Log Action of an Observable
1
2
3
4
5
6
7
8
9
10
11
//Provide an indication of which interval has action performed
const interval1 = Rx.Observable.interval(1000);
const example1 = interval1.do(val => console.log(`Early interval, second(s) elapsed! : ${val}`));

const interval = Rx.Observable.interval(2000);
const example2 = interval.do(val => console.log(`Later interval, second(s) elapsed! : ${val}\n`));

Observable.merge(
example1,
example2
).subscribe((x) => {});

No ‘default’ Call Needed when ‘requiring’ transpiled module from Babel

The require call in a ES5 transpiled module from ES6 requires you to call the ‘default’ key of the return function value before the actually functionality can be accessed:

More Boilerplate for 'Requiring' a Module
1
2
3
4
5
6
var fantasticModule = require('my-fantastic-module-name');
fantasticModule.default();

//Have to do the above instead of:
//var fantasticModule = require('my-fantastic-module-name');
//fantasticModule();

To solve this problem use the ‘babel-plugin-add-module-exports’ module from here.

After installing that module, require calls from an ES5 environment will no longer need to make the ‘default’ key access before calling.

Nodejs - Quick Tips #6

Babel - Requiring ES2015 File from ES5

In the situation where you desire to use a ES5 file to refer to a ES2015 file, the on-the-fly compilation option of Babel can be one of the ways to do so.

This case might come up when you are intending to run an init file that you do not want to perform any Babel compilation, but you still want the ES5 file to serve as the entry point for your module.

On the Fly Compilation
1
2
3
require('babel-core/register')({
presets: ['es2015']
});

This technique more suited for activities which do not need fast processing time because this method really slows execution down.

It will be more appropriate for operations that are not frequently run, such as some tests, and it would also not be advisable for initializing a cli node module because the slowdown will be quite evident.

As a side note for speeding up node cli execution, it is more beneficial to reduce the number of ‘require’ calls as noted here, which makes for the argument of using webpack to bundle your NPM modules into one file.

Testing Command Line NPM Modules

Most NPM modules are used programmatically through importing or requiring them into the file you are working on, but for the other times where your NPM module is used as a CLI module, input will need to be taken from the console.

For the properly testing of these CLI modules, the ‘childProcess.exec’ method can be used. The following example will starts the npm at the entry point

child_process
1
2
3
4
5
6
7
8
9
10
import childProcess from 'child_process';
const exec = childProcess.exec;

//Point to the entry point of NPM module
const cliEntryFile = 'node ' + __dirname + '/../bin/my-cli-init.js';

//Execute the command line with the supplied argument
exec(cliEntryFile + ' my-cool-command', function(error, stdout, stderr) {
//Rest of command actions
});

The above shows that node will execute the exact entry file (the ‘main’ key in package.json) with the command of your choice for your test cases.

Nodejs - Quick Tips #5

Process Exit and Time Elapse

When performing a long-running operation in the terminal, such as file generation, a user would like to know how long the task has ran.

A simple way to determine how much time has elapsed in general will be to listen to ‘exit’ event on the process object. This can be combined with the ‘hrtime’ method on the process object to provide a detailed time interval.

Using Built-In Nodejs Functions for Timing
1
2
3
4
5
6
let time = process.hrtime();

process.on('exit', () => {
let timeDiff = process.hrtime(time);
console.log('Time elapsed for file(s) and folder(s) generation: %d nanoseconds', timeDiff[0] * 1e9 + timeDiff[1]);
});

Babel Webpack Eslint Boilerplate

The JavaScript community has embraced ES2015 as the go-to JavaScript version to do modern web development. There are many Gulp and Babel boilerplates out there, but I found out that it is not as reliable as the Webpack and Babel combination because the Gulp watch tasks did not always pick up file changes for me.

Here is a simple config for creating a starter ES2015 JavaScript project.

package.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
"name": "my-great-module",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node_modules/webpack/bin/webpack.js --watch"
},
"author": "",
"license": "ISC",
"dependencies": {
"babel": "^6.5.2",
"babel-core": "^6.7.2",
"babel-eslint": "^6.0.2",
"babel-loader": "^6.2.4",
"babel-plugin-syntax-async-functions": "^6.5.0",
"babel-plugin-transform-runtime": "^6.6.0",
"babel-preset-es2015": "^6.6.0",
"babel-preset-stage-3": "^6.5.0",
"eslint": "^2.8.0",
"eslint-config-standard": "^5.1.0",
"eslint-loader": "^1.3.0",
"eslint-plugin-babel": "^3.2.0",
"eslint-plugin-promise": "^1.1.0",
"eslint-plugin-standard": "^1.3.2",
"webpack": "^1.12.14"
}
}

Async functions are actually a ES2016 feature, but they are a really useful functionality, so useful that I included it into the boilerplate.

Webpack is a module bundler and loader, but it can also perform file transformations for us. Webpack is our case, will be use to transpile ES2015 and for linting.

Webpack is configured with a webpack.config.js file:

webpack.config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var path = require('path');

module.exports = {
entry: './the-main-input-file.js',
output: {
path: path.join(__dirname, '/dist/'),
filename: 'my-output-file.js'
},
module: {
preLoaders: [
{test: /\.js$/, loader: "eslint-loader", exclude: /node_modules/}
],
loaders: [{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
}]
},
resolve: {
extensions: ['', '.config.js', '.js']
},
eslint: {
configFile: './.eslintrc.json'
},
babel: {
presets: ['es2015', 'stage-3']
}
};

By default, Webpack intends to have an entry point file which serves as a manifest file for all your JavaScript files to be transform to a single output file.

Now a .babelrc is required to configure how Babel is to transpile ES2015 JavaScript:

.babelrc
1
2
3
4
5
6
7
8
9
10
{
"presets": [
"stage-3",
"es2015"
],
"plugins": [
"transform-runtime",
"syntax-async-functions"
]
}

A stage-3 preset is needed for the async function feature in ES2016.

Lastly, for the eslintrc.json file, this will provide the rules for linting JavaScript:

eslintrc.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
{
"parser": "babel-eslint",
"parserOptions": {
"ecmaVersion": 7,
"sourceType": "module"
},
"plugins": [
"babel"
],
"root": true,
"ecmaFeatures": {
"arrowFunctions": true,
"binaryLiterals": true,
"blockBindings": true,
"classes": true,
"defaultParams": true,
"destructuring": true,
"forOf": true,
"generators": true,
"modules": true,
"objectLiteralComputedProperties": true,
"objectLiteralDuplicateProperties": true,
"objectLiteralShorthandMethods": true,
"objectLiteralShorthandProperties": true,
"octalLiterals": true,
"regexUFlag": true,
"regexYFlag": true,
"spread": true,
"superInFunctions": true,
"templateStrings": true,
"unicodeCodePointEscapes": true,
"globalReturn": true
},
"rules": {
"strict": 0,
"no-var": 2,
"comma-dangle": [2, "never"],
"no-cond-assign": [2, "always"],
"no-console": 0,
"no-debugger": 1,
"no-alert": 0,
"no-constant-condition": 1,
"no-dupe-keys": 2,
"no-duplicate-case": 2,
"no-empty": 0,
"no-ex-assign": 2,
"no-extra-boolean-cast": 1,
"no-extra-semi": 2,
"no-func-assign": 2,
"no-inner-declarations": 2,
"no-invalid-regexp": 2,
"no-irregular-whitespace": 2,
"no-obj-calls": 2,
"quote-props": 0,
"no-sparse-arrays": 2,
"no-unreachable": 2,
"use-isnan": 2,
"block-scoped-var": 2,
"quotes": [1, "single"],
"no-shadow": 0,
"no-shadow-restricted-names": 2,
"no-unused-vars": [0, {
"vars": "local",
"args": "after-used"
}],
"no-use-before-define": 2,
"consistent-return": 2,
"complexity": [2, 7],
"curly": [2, "multi-line"],
"default-case": 2,
"dot-notation": [2, {
"allowKeywords": true
}],
"eqeqeq": 2,
"guard-for-in": 0,
"no-caller": 2,
"no-else-return": 1,
"no-eq-null": 2,
"no-eval": 2,
"no-extend-native": 2,
"no-extra-bind": 2,
"no-fallthrough": 2,
"no-floating-decimal": 2,
"no-implied-eval": 2,
"no-lone-blocks": 2,
"no-loop-func": 1,
"no-multi-str": 2,
"no-native-reassign": 2,
"no-new": 2,
"no-new-func": 2,
"no-new-wrappers": 2,
"no-octal": 2,
"no-octal-escape": 2,
"no-param-reassign": 0,
"no-proto": 2,
"no-redeclare": 2,
"no-return-assign": 2,
"no-script-url": 2,
"no-self-compare": 2,
"no-sequences": 2,
"no-throw-literal": 2,
"no-with": 2,
"radix": 2,
"vars-on-top": 0,
"wrap-iife": [2, "any"],
"yoda": 2,
"indent": 0,
"brace-style": [2,
"1tbs", {
"allowSingleLine": true
}],
"quotes": [
0, "single", "avoid-escape"
],
"camelcase": [2, {
"properties": "never"
}],
"comma-spacing": [2, {
"before": false,
"after": true
}],
"comma-style": [2, "last"],
"eol-last": 0,
"key-spacing": [2, {
"beforeColon": false,
"afterColon": true
}],
"new-cap": [2, {
"newIsCap": true
}],
"no-multiple-empty-lines": [0, {
"max": 2
}],
"no-nested-ternary": 2,
"no-new-object": 2,
"no-spaced-func": 2,
"no-trailing-spaces": 2,
"no-extra-parens": 0,
"no-underscore-dangle": 0,
"one-var": [0, "never"],
"padded-blocks": 0,
"semi": [2, "always"],
"semi-spacing": [2, {
"before": false,
"after": true
}],
"keyword-spacing": 2,
"space-before-blocks": 2,
"space-before-function-paren": [2, "never"],
"space-infix-ops": 2,
"keyword-spacing": 2,
"spaced-comment": 0
}
}

Velocityjs - Effects

For your heavy-duty JavaScript animations, I recommend Velocityjs, since it has many features and great documentation.
Here are some simple effects that I find useful if you have chosen to use Velocityjs:

Pulsate / Throb

Grow and Shrink Element for Five Times
1
$('#my-element').velocity({ scale: 2 }, { loop: 5});

Pulsate Demo

Show and Rotate

Appear, Spins, and Disappear
1
2
//Complete animation within half a second
$('#my-element').velocity({ scale: 3, opacity: 1, rotateZ: "360deg" }, {duration: 500});

Spin Demo

Stagger Elements

Group Zoom-in
1
2
//Assumes that the UI Pack (velocity.ui.js) is in place
$('.group-of-elements').velocity('transition.whirlIn', {stagger: 500});

Stagger Group Demo