Skip to content

Instantly share code, notes, and snippets.

@dhval
Last active August 24, 2019 16:05
Show Gist options
  • Save dhval/1646ac665ca78d7e8af3 to your computer and use it in GitHub Desktop.
Save dhval/1646ac665ca78d7e8af3 to your computer and use it in GitHub Desktop.
Using bluebird promises
#!/usr/bin/env node
/**
Demostrate a practical use case with Bluebird promise api.
Read a line delimited file and store into sqlite3 db.
Promise.promisifyAll - Converting synchromous api's to Async.
Promise.using and Promise.disposer - Resource managment.
Promise.map and Promise.spread - Leveraging arrays in promises.
Notes:
1. You can forget everything but always remember to return something from callbacks !
2. I am prefferring named function expression over anoymous functions as it is easy to
ready and meaningful while debugging.
see:
http://bluebirdjs.com/docs/api
http://bluebirdjs.com/docs/api/disposer.html
see http://bluebirdjs.com/docs/api/promise.map.html
https://github.com/grumdrig/node-sqlite
**/
var fs = require('fs'),
path = require('path'),
Promise = require('bluebird'),
// Promisify all functions with async support.
sqlite3 = Promise.promisifyAll(require('sqlite3').verbose()),
patternUser = new RegExp("\\w*\\.\\w*"),
currentTime = new Date().getTime();
function fileRead(dir, file) {
// we can do this for kicks, Promise.promisify(fs.readFileSync)
return fs.readFileSync(path.join(dir, file), 'utf8', function(err, data) {
console.log(err + "err");
return data;
});
}
// Read a file containing user names, \n delimited. Filter out bad names.
var data = fileRead("/Users/dhval", "users.txt").split(/\n/)
.filter(function(user) {
return patternUser.test(user);
}).map(function(user) {
return user.replace(/[^a-zA-Z0-9.]/g, "");
});
// Returns a promise of user count with the given user name.
function userExists(con, userName) {
var promise = con.getAsync("select count(*) as count from user where user = ?", userName).then(function(row) {
return row.count;
}, function(err) {
console.log(err);
return -1;
});
return promise;
}
// Returns a promise of new connection.
function createConnection(dbFile) {
var connection = new sqlite3.Database(dbFile);
// Making sure a table exists or create one. By returning a connection we avoid anti pattern of creating promise within promise.
return connection.runAsync("CREATE TABLE if not exists user (id INT, user TEXT, pwd TEXT, createDt INT, updateDt INT)").then(function() {
return connection;
});
}
// Attaches a disposer to a promise.
function getConnection(dbFile) {
return createConnection(dbFile).disposer(function(connection, promise) {
if (connection) {
console.log("closing db connection, success=" + promise.isFulfilled());
connection.close();
}
});
}
// You can see from logs that everythinng happen in proper sequence. Still it has a race condition because of dirty reads.
Promise.using(getConnection('users.db'), function(connection) {
// Promise.dispose will be fired whenever we 'complete()' this promise.
var promise = new Promise(function(complete, reject) {
var stmt = connection['stmt'] = connection.prepare("INSERT INTO user(user, createDt) VALUES (?,?)");
console.log("count#" + data.length);
Promise.map(data, function(userId) {
return connection.getAsync("select count(*) as count from user where user = ?", userId).then(function(row) {
console.log("got results: " + userId + "#" + row.count);
return row.count ? row.count : 0;
}).then(function(count) {
if (count == 0) {
console.log("insert, " + userId);
return stmt.runAsync(userId, currentTime);;
} else {
// it is a good habbit to return something from callbacks.
return true;
}
});
}).spread(function() {
console.log("complete, calling disposers");
stmt.finalize();
complete();
}).catch(function(e) {
console.log(e);
})
});
return promise;
});
{
"name": "js-dev",
"version": "1.2.0",
"description": "cmd line JS scripts.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"bluebird": "^3.0.0",
"sqlite3": "^3.1.0"
}
}
<html>
<head>
<title>Hello World</title>
<script src="https://unpkg.com/react@15/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@15/dist/react-dom.js"></script>
</head>
<body>
<div id="root"></div>
<script>
window.onload = function()
{
class Greetings extends React.Component
{
render()
{
return React.createElement('h1', null, 'Greetings, ' + this.props.name + '!');
}
}
ReactDOM.render(
React.createElement(Greetings, { name : 'User' }),
document.getElementById('root')
);
};
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment