Eliminando Callback Hell em Node.js com Synchronize

Recentemente, tenho trabalhado em um aplicativo Node.js que utiliza MongoDB e me descobri amando e odiando o Node. A natureza assíncrona do Node torna o inferno de callback a ruína da minha existência. Em outras linguagens, espero métodos que retornam algo para … retornar algo.

MyObj o = MyClass.getMyObj();

Node (JavaScript) prefere nos fazer usar callbacks e aninhar tudo.

MyClass.getMyObj( function( err, obj) {
MyObj o = obj;
});

Tenho certeza de que isso tem seus benefícios, mas ao trabalhar com muitas operações de banco de dados, esses ninhos podem ficar muito profundos para gerenciar rapidamente. Felizmente, encontrei um bom módulo chamado Synchronize que alivia a maioria dessas dores, permitindo que você faça seu código se comportar de maneira síncrona. Não consegui encontrar um único exemplo funcional de como usar este módulo, então decidi compartilhar como estou usando.

Primeiro, você deve instalar o Synchronize

npm install synchronize

Em seguida, certifique-se de que requer o módulo. Eu também alias os métodos para salvar pressionamentos de tecla posteriormente:

var sync = require('synchronize');
var fiber = sync.fiber;
var await = sync.await;
var defer = sync.defer;

Então é realmente muito fácil pegar o jeito. Você apenas envolve seu código assíncrono em a fiber()e chama cada método assíncrono dentro de um await(), substituindo o retorno de chamada por defer().

try {
fiber
(function() {
var obj1 = await( someAsyncMethod( defer() ) );
var obj2 = await( anotherAsyncMethod( obj1, defer() ) );
var result = await( lastAsyncMethod( obj2, defer() ) );
});
} catch(err) {
//TODO Handle error
}

Para que você possa ter uma ideia dos benefícios de usar o Synchronize, aqui está o mesmo exemplo que seria sem o Synchronize.


someAsyncMethod
( function( err, result ) {
if(err)
//...
anotherAsyncMethod
( result, function( err, result ) {
if(err)
//...
lastAsyncMethod
( result, function( err, result ) {
if(err)
//...
// do something with result
});
});
});

Tenho certeza de que nem todos concordarão, mas acho isso muito mais desagradável de olhar do que o código síncrono.

Apenas por diversão, aqui está o exemplo escrito em CoffeeScript.

try
fiber
->
obj1
= await someAsyncMethod defer()
obj2
= await anotherAsyncMethod obj1, defer()
result
= await lastAsyncMethod obj2, defer()
catch err
# handle error

Tenho certeza que expliquei mal as coisas, mas espero que alguém possa achar isso útil. Além disso, se houver maneiras melhores de fazer as coisas para tornar o gerenciamento de retornos de chamada mais eficaz, me avise. Sou muito novo no Node e sempre gosto de aprender maneiras melhores de fazer as coisas!