Monday 5 October 2015

ES6: методы против коллбэков

Существует тонкое различие между объектом и методами объекта с обратных вызовов.

Объект, свойства которого являются методами

Параметр this метода является получателем вызова метода (например, obj если вызов метода obj.m (···)).

Например, вы можете использовать WHATWG потоков API следующим образом:


let surroundingObject = {
surroundingMethod() {
let obj = {
data: 'abc',
start(controller) {
···
console.log(this.data); // abc (*)
this.pull(); // (**)
···
},
pull() {
···
},
cancel() {
···
},
};
let stream = new ReadableStream(obj);
},
};


То есть, `obj` является объектом, свойства которого` start`, `и` pull` cancel` методы. Соответственно, эти методы можно использовать `this` для доступа к объектно-локального состояния (линия *) и называть друг друга (линии **).


Объект, свойства которого callbacks

Параметр `this` из функции стрелки является` this` окружающей рамки (лексический это). Arrow функции делать отличные Обратные вызовы, потому что это поведение обычно хотят для обратного вызова (реальной, не-метод функций). Обратный вызов не должен иметь свой собственный это, что тенями `this` окружающей области.

Если свойства `start`,` и `pull` cancel` являются стрелками функций, то они подобрать` `this` из surroundingMethod ()` (окружающей их охват):


let surroundingObject = {
surroundingData: 'xyz',
surroundingMethod() {
let obj = {
start: controller => {
···
console.log(this.surroundingData); // xyz (*)
···
},

pull: () => {
···
},

cancel: () => {
···
},
};
let stream = new ReadableStream(obj);
},
};
let stream = new ReadableStream();

Если выход в линии * удивляет вас, то рассмотрим следующий код:


let obj = {
foo: 123,
bar() {
let f = () => console.log(this.foo); // 123
let o = {
p: () => console.log(this.foo), // 123
};
},
}

Внутри метода bar(), f и o.p работать так же, потому что обе функции со стрелками имеют те же окружающий лексическую область bar(). Последняя функция стрелка в окружении объекта буквальном не изменить.

Friday 2 October 2015

NodeJS 4.0.0 8% быстрее - мы проверили его!

NodeJS и iojs встретились в середине и сталь одним проектом снова! Нет больше пытаются решить, какой из них использовать. Они также объявили о своих планах выпуска, которые интересно. Две большие релизы в год и в довершение, там будет версия LTS узла, который, мы надеемся, сделать прецедент легче в условиях, когда жизненные циклы больше.


Как вы знаете, мы большие поклонники Node здесь Raygun, поэтому подумал сделаю benchmark  Node 4.0.0 и определим насколка он быстрее!


Как тестировал


  • NodeJS и io.js работает на Mac OS X Yosemite, полностью в актуальном состоянии на частоте 2,5 ГГц i7 Macbook Pro с 16G оперативной памяти
  • Ubuntu VM, используя WRK, 12 потоки, 400 одновременных соединений более 30 секунд отправляя небольшой Raygun стиле полезную нагрузку в маленькую ExpressJS сайте, который возвращает то, что отправил на него

Каждый тест проводился в 5 раз и затем усредняются, чтобы получить число ниже. Как и во всех тестах, они могут быть только по сравнению с результатами в этом наборе.


Если вы следили за Node / io.js на некоторое время теперь, вы будете знать, что последняя версия использует последнюю версию V8, который включает в себя кучу новых ECMA 6 функций. Он также должен быть быстрее, будучи новым.



С самого быстрого теста здесь, Node 4.0.0 около 8% быстрее, чем Node 0.12.7 При работе с той же нагрузке. Это не плохо для простого обновления, особенно если умножить его на нескольких серверах!

Dependency Injection в Node.js

Dependency injection is a software design pattern in which one or more dependencies (or services) are injected, or passed by reference, into a dependent object.

Причины для использования Dependency Injection


Развязка


Внедрение зависимостей делает ваши модули менее связаны приводит к более обслуживаемой кода.


Легче модульного тестирования


Вместо того чтобы использовать жестко закодированные зависимостей вы можете передать их в модуль вы хотели бы использовать. С этой картины в большинстве случаев, вы не должны использовать модули, как proxyquire.


Ускорение разработки


С инъекции зависимостей, после интерфейсы определены легко работать без каких-либо конфликтов слияния.


Как использовать Dependency Injection используя Node.js


Во-первых, давайте взглянем на то, как вы могли бы написать свои приложения без использования инъекции зависимостей, и как бы вы преобразовать его.


Образец модуля без dependency injection


// team.js
var User = require('./user');

function getTeam(teamId) {  
  return User.find({teamId: teamId});
}

module.exports.getTeam = getTeam;  

Простой тест будет выглядеть так:


// team.spec.js
var Team = require('./team');  
var User = require('./user');

describe('Team', function() {  
  it('#getTeam', function* () {
    var users = [{id: 1, id: 2}];

    this.sandbox.stub(User, 'find', function() {
      return Promise.resolve(users);
    });

    var team = yield team.getTeam();

    expect(team).to.eql(users);
  });
});

То, что мы сделали здесь является то, что мы создали файл с именем team.js, которые могут возвращать список пользователей, которые принадлежат к одной команде. Для этого нам потребуется модель User, так что мы можем вызвать его метод, который возвращает find список пользователей.


Выглядит хорошо, не так ли? Но когда дело доходит до тестирования, мы должны использовать тестовые заглушки с sinon.


В тестовом файле, мы должны потребовать модель User, так что мы можем заглушки свой метод find. Заметьте, что мы используем функцию песочницы здесь, так что мы не придется вручную восстановить исходную функцию после выполнения теста.


Sample module with dependency injection


/ team.js
function Team(options) {  
  this.options = options;
}

Team.prototype.getTeam = function(teamId) {  
  return this.options.User.find({teamId: teamId})
}

function create(options) {  
  return new Team(options);
}

Вы можете проверить это файл со следующим теста:


// team.spec.js
var Team = require('./team');

describe('Team', function() {  
  it('#getTeam', function* () {
    var users = [{id: 1, id: 2}];

    var fakeUser = {
      find: function() {
        return Promise.resolve(users);
      }
    };

    var team = Team.create({
      User: fakeUser
    });

    var team = yield team.getTeam();

    expect(team).to.eql(users);
  });
});

Хорошо, так как версия с инъекции зависимостей отличается от предыдущей? Первое, что можно заметить, является использование factory pattern: мы используем это, чтобы придать вариантов / зависимостей для вновь созданного объекта - это когда мы можем придать модели User.


В тестового файла мы должны создать поддельный модель, которая будет представлять модель User, то мы просто ввести это путем передачи его в create функции Team модели. Легко, не так ли?


Dependency Injection в реальных проектах


Вы можете найти примеры внедрения зависимостей в много проектов с открытым кодом. Например, большинство Express/Koa middlewares, которые вы используете в вашей повседневной работе использует ту же самую подход.


Express middlewares


var express = require('express');  
var app = express();  
var session = require('express-session');

app.use(session({  
  store: require('connect-session-knex')()
}));

Фрагмент кода выше, используя зависимость инъекций с заводской схеме: на сессии промежуточного мы передаем модуль connect-session-knex - он должен реализовать интерфейс, что модуль session будет звонить.


В этом случае модуль connect-session-knex должен реализовать следующие методы:


  • store.destroy(sid, callback)
  • store.get(sid, callback)
  • store.set(sid, session, callback)