Имитация $.Deferred под node.js
Nov. 13th, 2014 10:01 pm
Придумалась тут на днях офигенная концепция как на клиенте, в браузере, разрабатывать и отлаживать серверный js-код, работающий с БД. Из картиночки справа в общем всё понятно.
В нашем типичном стеке серверных технологий – node.js + express + cradle + CouchDB – достаточно заменить только cradle.js на PouchDB.
Обвес, позволяющий проделывать весь этот трюк в браузере, оказался на удивление несложным в целом. Я его как proof of concept написал за вечер, а на следующий вечер у меня уже заработал серверный код, полностью написанный в нашей самопальной IDE.
Как ни странно, всё взлетело сразу почти, без особого бубна с функционалом БД. Споткнулся я сначала на криптографии, но это мы проработали прошлой зимой, оставалось только чуток подкрутить. Гораздо более серьёзным оказался затык на библиотеке, обеспечивающий Promise-функционал нужного синтаксиса.
Промисы – модная и очень удобная штука, мы активно используем. Коллбэки – фу, промисы – кул. Беда в том, что синтаксис промисов иногда существенно отличается от библиотеки к библиотеке, там нет единого стандарта.
Исторически так сложилось, что на клиенте мы используем модель jQuery.Deferred – которая не очень то удачна, по-честному. Ну и оказалось что для node.js нет либы, которая повторяла бы синтаксис $.Deferred – чему я был очень удивлён.
В результате перебора bluebird.js, затем lie.js [ага, var Promise = require("lie")] и затем Q.js оказалось, что проще всего имитировать $.Deferred под нодом с помощью Q. Ну, как известно “то, что вы ищете, вы найдёте в самом последнем месте”, да.
Так вот, в самом простейшем варианте код выделки симулякра $.Deferred из Q.defer умещается в 20 строк:
var Q = require("q");
var Promise = function(){
var q = Q.defer(),
qp = q.promise,
pi = {
then:function(a,b){return qp.then(a,b);},
fail:function(a,b){return qp.fail(a,b);},
done:function(a,b){return qp.done(a,b);},
progress:function(a,b){return qp.progress(a,b);},
promise: function(){return q.promise;},
resolve:function(a,b){q.resolve(a,b); return pi;},
reject:function(a,b){q.reject(a,b); return pi;},
notify:function(a,b){q.notify(a,b); return pi;},
isResolved:function(a,b){return q.isFulfilled(a,b);},
isRejected:function(a,b){return q.isRejected(a,b);},
state: function(){
var state = qp.inspect().state;
return state==="fulfilled"?"resolved":state;
}
};
return pi;
}Если не заигрывать сильно с this, не засовывать синхронный код в промис и использовать только базовый синтаксис, этого достаточно. Вдруг кому пригодится.
Сегодня кста выяснилось, что node.js даже последних сборок использует уже не поддерживаемую Гуглом версию V8. А нод много где в продакшене используется о_О