Upload
mongodb
View
150
Download
1
Embed Size (px)
Citation preview
ECMAScript 6 and the Node Driver
3
Agenda
• ES6• ES6 Features• MongoDB Core• ES6 Prototype• Performance
4
Good Evening
Christian Amor KvalheimDrivers Lead and Node.js driver author
Oviedo, Spain
@christkv
http://www.christiankvalheim.com
ES6
6
ES6
• ES6 Is a fundamental rethink of the JavaScript language• Introduces a lot of new features
– Iterators– Generators– Proxies– Promises– Classes– and much more….
ES6 Features
8
Classes
• Classes are syntactic sugar on top of JavaScript existing prototype based inheritance.
• Classes do not introduce a new Object Oriented inheritance model.
• Classes simplify the code and provides a clearer syntax for prototype based inheritance.
9
Classes
• ES6 Introduces classes
class Cursor { constructor() {}
count() {}}
10
Classes
• ES6 Introduces classes
class SpecialCursor extends Cursor { constructor() { super(); }}
11
Iterators
• Iterators are created using a protocol allowing JavaScript objects to define or customize their iteration behavior.
• Arrays in ES6 are now iterators and can be used in the new for-of construct.
• An object is an Iterator when it implements a next() method that returns an object with two properties.– done (boolean)– value (any JavaScript value)
12
Iterators
class Next { constructor(value) { this.value = value || 0; }}
Next.prototype[Symbol.iterator] = function() { var cur = this.value;
return { next() { return {done: false, value: cur++} } } }
for(var n of new Next()) { if(n == 1000) break;}
13
Promises
• A Promise is an object used for deferred and asynchronous computations.
• A promise can either be fulfilled with a value or rejected.• Promises can be chained using then.• Execute n promises using Promise.all.• Very useful to orchestrate asynchronous operations.• Allows for easier reasoning of call chains.
14
Promises
var p2 = new Promise(function(resolve, reject) { resolve(2);});
p2.then(function(value) { assert(2, value);});
var promise = Promise.resolve(3);Promise.all([true, promise]) .then(function(values) { console.log(values); });
15
Generators
• A Generator is a function that can be exited, and then later re-entered.
• The context of the function is saved across re-entrances.• Calling a Generator function returns an iterator object.• Calling next on the iterator executes the function until the
first yield is encountered.
16
Generators
class Next { constructor(value) { this.value = value || 0; }}
Next.prototype[Symbol.iterator] = function*() { var cur = this.value;
while(true) { yield cur++; }}
for(var n of new Next()) { if(n == 1000) break;}
17
Generators + co
• co library– Runs a generator to the end– Expects to yield on promises– Simplifies the syntax for programming
18
Generators + co
var co = require('co'), assert = require('assert');
var p1 = new Promise(function(resolve, reject) { resolve(2);});
co(function*() { var value = yield p1; assert.equal(2, value);}).catch(function(err) { console.dir(err)});
19
Proxies
• Proxies allows a user to override fundamental behaviors of an object– Property lookup– Assignment– Function calls– Enumeration
• Proxies is close to method_missing in ruby.• Proxies can lead to slow execution if in critical code path.
20
Proxies
var handler = { get: function(target, name){ return name in target ? target[name] : 37; }};
var p = new Proxy({}, handler);p.a = 1;p.b = undefined;
console.log(p.a, p.b); // 1, undefinedconsole.log('c' in p, p.c); // false, 37
MongoDB Core
22
MongoDB Core
• MongoDB Core is a low level driver wrapping the wire protocol and authentication– No abstractions
• MongoDB Core was developed to allow for people to more easily write– ODMs (Object Document Modeling)– Driver Wrappers– Tools/Frameworks
23
Simple Example
var Server = require('mongodb-core').Server;
// Attempt to connectvar server = new Server({ host: 'localhost', port: 27017 })
// Add event listenersserver.on('connect', function(server) { // Execute the command server.command("system.$cmd" , {ismaster: true}, function(err, result) { server.destroy(); });});
server.connect();
24
Mongodb-core
• install
npm install mongodb-core
• Tested on– Node 12.2– IO.js 2.0
• https://github.com/christkv/mongodb-core
ES6 Prototype
26
ES6 Prototype
• Prototype aims to explore the ES6 space to improve the usability of the driver.– Leverage only the features of ES6 that improves
productivity– Ensure no significant performance degradation
happens in the transition from ES5 to ES6
27
FROM
var MongoClient = require(‘mongodb’).MongoClient, assert = require(‘assert’);
MongoClient.connect(‘mongodb://localhost:27017/test’ , function(e, d) { assert.equal(null, e); var c = d.collection(‘test1’); c.insertOne({a:1}, function(e, r) { assert.equal(null, e);
c.find({}).toArray(function(e, docs) { assert.equal(null, e); assert.equal(1, docs.length); d.close(); }); });});
28
TO
var MongoClient = require(’mongodb-es6').MongoClient, co = require(‘co’);
co(function* () { var client = yield new MongoClient('mongodb://localhost:27017/test', {}).connect()
try { var result = yield client['tests']['cursors'].insertOne({a:2}); } catch(err) {};
var docs = yield client['tests']['cursors'].find({}).toArray();}).catch(function(err) { console.dir(err)});
29
ES6 Driver Design
• Driver uses MongoDB Core as it’s bases.• Driver leverages the following features of ES6
– Classes– Promises
• Forward compatible with co• Forward compatible with ES7 async/await
– Proxies
30
Classes
• Prototype has classes for– Db– Collection– Cursor– AggregationCursor– CommandCursor– MongoClient
• Prototype has a minimal API
31
Promises
• Prototype returns a Promise for all asynchronous methods, no callbacks.command(cmd) { var self = this;
return new this.options.promise(function(resolve, reject) { self.topology.command(f('%s.$cmd', self.name), cmd, function(err, r) { if(err) reject(err); else resolve(r); }); });}
32
Promises
• Prototype returns standard ES6 promises• Bring Your Own Promises (BYOP)
var MongoClient = require(’mongodb-es6').MongoClient , P = require("bluebird");
co(function* () { var client = yield new MongoClient('mongodb://localhost:27017/test’)
.promiseLibrary(P).connect();});
33
Promises + Iteration
• Iterating a cursor is completely different from 2.x
var MongoClient = require(’mongodb-es6').MongoClient , P = require("bluebird");
co(function* () { var client = yield new MongoClient('mongodb://localhost:27017/test’)
.promiseLibrary(P).connect(); var cursor = client[‘tests’][‘docs’].find({});
while(yield cursor.hasNext()) { console.dir(yield cursor.next()); }}).catch(function(err) { console.dir(err);});
34
Proxies
• Prototype uses proxies to allow for simpler access to databases allowing you to do.var MongoClient = require(’mongodb-es6').MongoClient, co = require(‘co’);
co(function* () { var client = yield new MongoClient('mongodb://localhost:27017/test', {}).connect();
var testsDb = yield client['tests’]; var cursorsCollection = yield testsDb['cursors’]}).catch(function(err) { console.dir(err)});
35
Proxies Gotchas
• Proxies come with some performance implications.• Proxies are inherently poison to the way V8 JITs into
stable classes as a proxy wrapped instance can be x possible classes forcing de-optimizations.for(var i = 0; i < 10; i++) { yield client[‘tests’][‘docs’].insertOne({a:1});}
var col = client[‘tests’][‘docs’];for(var i = 0; i < 10; i++) { yield col.insertOne({a:1}) }
Performance
37
Performance
2.0 (IO 2.0) simple_100_document_toArray
Average 0.414 ms
Standard Deviation 0.498 ms
ES6 (IO 2.0) simple_100_document_toArray
Average 0.415 ms
Standard Deviation 0.501 ms
Release Information
39
Release Information
• Prototype install
npm install mongodb-es6
• Tested on– Node 12.2– IO.js 2.0
• https://github.com/christkv/mongodb-es6
One MoreThing
41
2.1- alpha with Promises
• 2.1- alpha install
npm install [email protected]
• https://github.com/mongodb/node-mongodb-native
42
Simple 2.1-alpha Example
var MongoClient = require(’mongodb'), Promise = require('bluebird');
MongoClient.connect(configuration.url(), { promiseLibrary: Promise}).then(function(db) { var promise = db.collection('test').insert({a:1}); test.ok(promise instanceof Promise);
promise.then(function() { db.close(); test.done(); });});