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)