Suponha que você mantenha uma biblioteca que expõe uma função getData
. Seus usuários chamá-lo para obter dados reais:
var output = getData();
Sob a dados capô é salvo em um arquivo para que você implementado getData
usando Node.js built-in fs.readFileSync
. É óbvio ambos getData
e fs.readFileSync
são funções de sincronização. Um dia, foi solicitado que você alternasse a fonte de dados subjacente para um repositório como o MongoDB, que só pode ser acessado de forma assíncrona. Você também foi instruído a evitar irritar seus usuários. A getData
API não pode ser alterada para retornar apenas uma promessa ou exigir um parâmetro de retorno de chamada. Como você atende a ambos os requisitos?
Função assíncrona usando retorno de chamada / promessa é o DNA de JavasSript e Node.js. Qualquer aplicativo JS não trivial provavelmente é permeado por esse estilo de codificação. Mas essa prática pode facilmente levar à chamada pirâmide de destruição de retorno de chamada. Pior ainda, se qualquer código em qualquer chamador na cadeia de chamadas depende do resultado da função assíncrona, esse código também deve ser envolvido na função de retorno de chamada, impondo uma restrição de estilo de codificação ao chamador. De tempos em tempos, acho necessário encapsular uma função assíncrona (geralmente fornecida em uma biblioteca de terceiros) em uma função de sincronização para evitar uma re-fatoração global maciça. Procurar uma solução sobre esse assunto geralmente terminava com fibras de nóou pacotes npm derivados dele. Mas as fibras simplesmente não conseguem resolver o problema que estou enfrentando. Até o exemplo fornecido pelo autor da Fibers ilustrou a deficiência:
...
Fiber(function() {
console.log('wait... ' + new Date);
sleep(1000);
console.log('ok... ' + new Date);
}).run();
console.log('back in main');
Saída real:
wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
back in main
ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)
Se a função Fiber realmente transformar a função assíncrona em suspensão em sincronização, a saída deverá ser:
wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)
back in main
Eu criei outro exemplo simples no JSFiddle e procurando por código para produzir a saída esperada. Aceitarei uma solução que só funcione no Node.js, para que você possa solicitar qualquer pacote npm, apesar de não trabalhar no JSFiddle.
Respostas:
O deasync transforma a função assíncrona em sincronização, implementada com um mecanismo de bloqueio, chamando o loop de eventos Node.js. na camada JavaScript. Como resultado, o deasync apenas bloqueia a execução do código subseqüente sem bloquear o encadeamento inteiro, nem gera a espera ocupada. Com este módulo, aqui está a resposta para o desafio jsFiddle:
(isenção de responsabilidade: eu sou o co-autor de
deasync
. O módulo foi criado após a postagem desta pergunta e não encontrou nenhuma proposta viável.)fonte
function AnticipatedSyncFunction(){ var ret; setTimeout(function(){ var startdate = new Date() //console.log(startdate) ret = "hello" + startdate; },3000); while(ret === undefined) { require('deasync').runLoopOnce(); } return ret; } var output = AnticipatedSyncFunction(); var startdate = new Date() console.log(startdate) console.log("output="+output);
e espero ver 3 segundos de diferença na saída da data!Também existe um módulo de sincronização npm. que é usado para sincronizar o processo de execução da consulta.
Quando você deseja executar consultas paralelas de maneira síncrona, o nó é restrito para fazer isso porque nunca espera pela resposta. e o módulo de sincronização são muito perfeitos para esse tipo de solução.
Código de amostra
link de referência: https://www.npmjs.com/package/sync
fonte
Sim. Dentro da fibra, a função aguarda antes do log
ok
. As fibras não tornam as funções assíncronas síncronas, mas permitem escrever código com aparência síncrona que usa funções assíncronas e, em seguida, serão executadas de forma assíncrona dentro de aFiber
.Você não pode. É impossível tornar o código assíncrono síncrono. Você precisará antecipar isso em seu código global e escrevê-lo no estilo assíncrono desde o início. Se você agrupa o código global em uma fibra, usa promessas, geradores de promessas ou retornos de chamada simples, depende de suas preferências.
Promessas e fibras podem fazer isso.
fonte
fs
métodos síncronos .Você precisa usar promessas:
Eu gosto mais de definições de funções de seta. Mas qualquer string do formato "() => {...}" também pode ser escrita como "function () {...}"
Portanto, o topDog não é assíncrono, apesar de chamar uma função assíncrona.
Edição: Eu percebo muitas vezes que você precisa para quebrar uma função assíncrona dentro de uma função de sincronização está dentro de um controlador. Para essas situações, aqui está um truque de festa:
Utilizando isso com retornos de chamada, você pode executar um wrap que não use promessas:
Ao aplicar esse truque a um EventEmitter, você pode obter os mesmos resultados. Defina o ouvinte do EventEmitter onde defini o retorno de chamada e emita o evento em que chamei o retorno de chamada.
fonte
Não consigo encontrar um cenário que não possa ser resolvido usando fibras de nó. O exemplo que você forneceu usando fibras de nó se comporta conforme o esperado. A chave é executar todo o código relevante dentro de uma fibra, para que você não precise iniciar uma nova fibra em posições aleatórias.
Vamos ver um exemplo: Digamos que você use alguma estrutura, que é o ponto de entrada do seu aplicativo (você não pode modificar essa estrutura). Essa estrutura carrega os módulos nodejs como plug-ins e chama alguns métodos nos plug-ins. Digamos que essa estrutura aceite apenas funções síncronas e não use fibras por si só.
Há uma biblioteca que você deseja usar em um de seus plug-ins, mas essa biblioteca é assíncrona e você também não deseja modificá-la.
O encadeamento principal não pode ser produzido quando nenhuma fibra está em execução, mas você ainda pode criar plugins usando fibras! Basta criar uma entrada de wrapper que inicie toda a estrutura dentro de uma fibra, para que você possa executar a execução a partir dos plug-ins.
Desvantagem: se a estrutura usa
setTimeout
ouPromise
s internamente, ela escapará do contexto da fibra. Isso pode ser contornado zombandosetTimeout
,Promise.then
e todos os manipuladores de eventos.Portanto, é assim que você pode produzir uma fibra até que uma
Promise
seja resolvida. Este código utiliza uma função assíncrona (retorno da promessa) e retoma a fibra quando a promessa é resolvida:framework-entry.js
async-lib.js
my-plugin.js
my-entry.js
Quando você executa
node framework-entry.js
ele irá lançar um erro:Error: yield() called with no fiber running
. Se você executar,node my-entry.js
ele funcionará conforme o esperado.fonte
A sincronização de código do Node.js. é essencial em alguns aspectos, como banco de dados. Mas a vantagem real do Node.js está no código assíncrono. Como é um thread único sem bloqueio.
podemos sincronizá-lo usando funcionalidades importantes Fiber () Use waitit () e defer () que chamamos de todos os métodos usando waitit (). substitua as funções de retorno de chamada por defer ().
Código assíncrono normal. Isso usa funções de retorno de chamada.
Sincronize o código acima usando Fiber (), waitit () e adiado ()
Espero que isso ajude. Obrigado
fonte
Atualmente, esse padrão de gerador pode ser uma solução em muitas situações.
Aqui um exemplo de console seqüencial solicita no nodejs usando a função assíncrona readline.question:
fonte
Você não deve olhar para o que acontece em torno da chamada que cria a fibra, mas para o que acontece dentro da fibra. Uma vez dentro da fibra, você pode programar no estilo de sincronização. Por exemplo:
No interior da fibra que você chama
f1
,f2
esleep
como se fossem sincronizados.Em um aplicativo Web típico, você criará o Fiber no seu despachante de solicitações HTTP. Depois de fazer isso, você poderá gravar toda a lógica de manipulação de solicitações no estilo de sincronização, mesmo que ela chame funções assíncronas (fs, bancos de dados etc.).
fonte
while(true) handleNextRequest()
loop. Encapsular cada manipulador de solicitação em uma fibra faria isso.Lutei com isso no começo com o node.js e o async.js é a melhor biblioteca que encontrei para ajudá-lo a lidar com isso. Se você deseja escrever código síncrono com o nó, a abordagem é assim.
este programa SEMPRE produzirá o seguinte ...
fonte
async
funciona no seu exemplo porque émain
, o que não se importa com o chamador. Imagine que todo o seu código está envolvido em uma função que deve retornar o resultado de uma de suas chamadas de função assíncronas. Pode ser facilmente comprovado que não funciona, adicionandoconsole.log('return');
no final do seu código. Nesse caso, a saída dereturn
acontecerá depois,in main
mas antesstep 1
.Javascript é uma linguagem única, você não deseja bloquear todo o servidor! O código assíncrono elimina as condições de corrida, explicitando as dependências.
Aprenda a amar código assíncrono!
Dê uma olhada no
promises
código assíncrono sem criar uma pirâmide do inferno de retorno de chamada. Eu recomendo a biblioteca promessaQ para node.jshttp://howtonode.org/promises
EDIT: esta é de longe a minha resposta mais controversa, o nó agora possui yield keyword, que permite tratar o código assíncrono como se fosse síncrono. http://blog.alexmaccaw.com/how-yield-will-transform-node
fonte