Fibras de Nó e Callbacks Assíncronos
por Neil Lobo, Engenheiro de Software
Parte da popularidade do Node.js é o ciclo de eventos. Ao invés de adotar a abordagem multithreaded dos frameworks tradicionais, Node.js usa um modelo de I/O não bloqueado, impulsionado por eventos. Isso lhe dá uma pegada de memória mais leve, é mais leve e eficiente, e é bem dimensionado para aplicações de dados intensivas em tempo real.
Esta abordagem de não bloqueio orientada por eventos funciona bem para aplicações onde o gargalo é E/S ou atividade de rede. Em contraste, se a aplicação requer tarefas intensivas de CPU, então o Node.js é provavelmente uma má escolha.
No entanto, trabalhar com o Node.js nu requer o uso de callbacks assíncronos que levam ao infame inferno da callback. Isto leva à lógica que é difícil de seguir.
//Callback Soup/Spiral Callback of Doom
function doAsync1(function () {
doAsync2(function () {
doAsync3(function () {
doAsync4(function () {
//finally do something });
});
});
});
O tratamento de erros e as chamadas aninhadas são desconfortáveis de escrever, e a sua existência torna o código difícil de manter e de escalar. Existem algumas técnicas para superar estes problemas, sendo as mais populares as Fibras e Promessas. Eu quero discutir a primeira, pois o Meteoro usa Fibras para alcançar código sincrônico como código sobre o loop do evento.
Fibras
Para aqueles que não estão familiarizados com ela, Fibers é uma construção de Computer Science que utiliza um modelo de multitarefa cooperativa (ao contrário dos threads utilizam multitarefa preventiva)
O código roscado pode ser interrompido em qualquer ponto, mesmo no meio da avaliação de uma expressão, para dar ciclos de CPU a códigos em execução em outra thread. Com fibras, essas interrupções e interrupções de contexto não são determinadas pela CPU ou por um processo de nível inferior; elas são determinadas pelo programador que decide onde seu código vai render e dar ciclos de CPU a outras fibras.
Aqui está um exemplo do típico código Node.js que usa uma função callbackFunction que é passada o resultado.
getDataFromDisk = function(fileName, key, callbackFunction) {
resultado da var;
fs.readFile('/path/fileName', function(err, res) {
if (err) console.log(err); else {
result = transform(res, key);
callbackFunction(result);
}}};
Vamos tentar escrever isto num estilo mais sincrónico.
getDataFromDisk = function(fileName, key) {
var result;
fs.readFile('/path/fileName', function(err, res) {
if (err) console.log(err); else result = transform(res, key);
}
resultado do retorno;// será sempre indefinido
};
// Tentamos usar getDataFromDisk devolver o valor, então
// imprimir, tudo em sincronia.
var resultado = getDataFromDisk('helloWorld',key);
console.log(resultado);
// indefinido
O código acima sempre retornará indefinido, pois o loop do evento irá passar para a linha de resultado de retorno (*) sem esperar pelo resultado da chamada de retorno.
Usando Fibras
As fibras são uma classe de funções de contentor que pode ser usada para bloquear uma sub-rotina enquanto se aguarda alguma E/S ou actividade de rede sem bloquear todo o processo.
var Fiber = Npm.require('fibers');// getDataFromDisk function using Fibers
getDataFromDisk = function(filename, key) {var fiber = Fiber.current; //get the current Fiber
fs.readFile('/path/fileName', function(err, res) {
if (err) console.log(err); else{
/* Resume execution of this fiber. What’s passed to fiber.run will become the value returned by Fiber.yield below */
fiber.run( transform(res, key) );
var result = Fiber.yield();
return result;};
// Finally we wrap our code in a Fiber, then run it
Fiber(function() {
var resultado = getDataFromDisk('helloWorld', key);
console.log(resultado);
}).run();
Presto, temos um código de aparência síncrona que ainda está sendo executado de forma assíncrona no loop de eventos.
Para mais detalhes sobre as Fibras, confira (https://github.com/laverdet/node-fibers)
