1. Análise de abertura
O fluxo é uma interface abstrata implementada por muitos objetos no nó. Por exemplo, uma solicitação para um servidor HTTP é um fluxo e o stdout também é um fluxo. Os fluxos são legíveis, graváveis ou ambos.
O primeiro contato com o fluxo começou com o UNIX inicial. Décadas de prática provaram que a idéia do Stream pode simplesmente desenvolver alguns sistemas enormes.
No UNIX, o fluxo é implementado através de "|". No nó, como um módulo de fluxo embutido, são usados muitos módulos principais e módulos de três partes.
Como o Unix, a operação principal do fluxo de nós é .pipe () e os usuários podem usar o mecanismo de contrapressão para controlar o equilíbrio entre leitura e gravação.
O fluxo pode fornecer aos desenvolvedores uma interface unificada que pode reutilizar e controlar o equilíbrio de leitura e gravação entre fluxos através de interfaces de fluxo abstrato.
Uma conexão TCP é um fluxo legível e um fluxo gravável, enquanto uma conexão HTTP é diferente. Um objeto de solicitação HTTP é um fluxo legível, enquanto um objeto de resposta HTTP é um fluxo gravável.
O processo de transmissão de fluxo é transmitido na forma de um buffer por padrão, a menos que você defina outros formulários de codificação, o seguinte é um exemplo:
A cópia do código é a seguinte:
var http = requer ('http');
var server = http.createServer (function (req, res) {
Res.WriteHeader (200, {'content-type': 'text/planing'});
res.nd ("Olá, grande urso!");
});
Server.Listen (8888);
console.log ("servidor http em execução na porta 8888 ...");
Após a execução, o código Globle aparecerá porque o conjunto de caracteres especificado não está definido, como: "UTF-8".
Apenas modifique:
A cópia do código é a seguinte:
var http = requer ('http');
var server = http.createServer (function (req, res) {
Res.WriteHeader (200, {
'Content-type': 'text/plana; charset = utf-8' // add charset = utf-8
});
res.nd ("Olá, grande urso!");
});
Server.Listen (8888);
console.log ("servidor http em execução na porta 8888 ...");
Resultados em execução:
Por que usar o fluxo
A E/S no nó é assíncrona; portanto, ler e escrever para disco e rede requer leitura e leitura de dados por meio de funções de retorno de chamada. A seguir é um exemplo de download de um arquivo
No código:
A cópia do código é a seguinte:
var http = requer ('http');
var fs = requer ('fs');
var server = http.createServer (function (req, res) {
fs.readfile (__ dirname + '/data.txt', function (err, dados) {
res.nd (dados);
});
});
Server.Listen (8888);
O código pode implementar as funções necessárias, mas o serviço precisa armazenar em cache os dados inteiros do arquivo para a memória antes de enviar os dados do arquivo. Se o arquivo "data.txt" for muito
Se for grande e tiver uma grande simultaneidade, muita memória será desperdiçada. Como o usuário precisa esperar até que todo o arquivo seja armazenado em cache na memória para aceitar os dados do arquivo, isso leva a
A experiência do usuário é muito ruim. Felizmente, ambos os parâmetros (req, res) são fluxo, para que possamos usar o fs.createReadstream () em vez de fs.readfile (). do seguinte modo:
A cópia do código é a seguinte:
var http = requer ('http');
var fs = requer ('fs');
var server = http.createServer (function (req, res) {
var stream = fs.creteReadstream (__ dirname + '/data.txt');
stream.pipe (res);
});
Server.Listen (8888);
O método .pipe () ouve os eventos 'dados' e 'end' do fs.createReadstream (), para que o arquivo "data.txt" não precise ser armazenado em cache.
Um arquivo pode ser enviado ao cliente imediatamente após a conclusão da conexão do cliente. Outro benefício de usar .pipe () é que ele pode ser resolvido quando um cliente
Leia e escreva desequilíbrio causado por um atraso final muito grande.
Existem cinco fluxos básicos: legível, gravável, transformada, duplex e "clássico". (Por favor, verifique a API para obter detalhes)
2. Apresente exemplos
Quando os dados que precisam ser processados não podem ser carregados na memória ao mesmo tempo ou quando o processamento é mais eficiente durante a leitura, precisamos usar fluxos de dados. O NodeJS fornece operações nos fluxos de dados através de vários fluxos.
Tomando o grande programa de cópia de arquivo como exemplo, podemos criar um fluxo de dados somente leitura para a fonte de dados, o exemplo é o seguinte:
A cópia do código é a seguinte:
var rs = fs.cretereadstream (nome do caminho);
rs.on ('dados', função (chunk) {
doSomething (pedaço); // Use os detalhes específicos como você deseja
});
rs.on ('end', function () {
limpar() ;
});
Os eventos de dados no código serão acionados continuamente, independentemente de a função doSomething ser processada. O código pode ser modificado da seguinte forma para resolver esse problema.
A cópia do código é a seguinte:
var rs = fs.cretereadstream (src);
rs.on ('dados', função (chunk) {
rs.Pause ();
doSomething (Chunk, function () {
rs.resume ();
});
});
rs.on ('end', function () {
limpar();
});
Um retorno de chamada é adicionado à função DoSomething, para que possamos pausar a leitura de dados antes de processar dados e continuar lendo os dados após o processamento de dados.
Além disso, também podemos criar um fluxo de dados somente de gravação para o destino de dados, como segue:
A cópia do código é a seguinte:
var rs = fs.cretereadstream (src);
var ws = fs.createwritSTream (DST);
rs.on ('dados', função (chunk) {
ws.write (pedaço);
});
rs.on ('end', function () {
ws.end ();
});
Depois que o que é substituído por escrever dados no fluxo somente de gravação, o código acima se parece com um programa de cópia de arquivo. No entanto, o código acima tem os problemas mencionados acima. Se a velocidade de gravação não puder acompanhar a velocidade de leitura, apenas escrever o cache dentro do fluxo de dados explodirá. Podemos julgar se os dados recebidos foram gravados no alvo ou temporariamente colocados no cache com base no valor de retorno do método .Write, e julgar quando apenas os dados de gravação foram gravados no destino com base no evento de drenagem e passar nos próximos dados a serem gravados. Portanto, o código é o seguinte:
A cópia do código é a seguinte:
var rs = fs.cretereadstream (src);
var ws = fs.createwritSTream (DST);
rs.on ('dados', função (chunk) {
if (ws.write (chunk) === false) {
rs.Pause ();
}
});
rs.on ('end', function () {
ws.end ();
});
ws.on ('drenagem', function () {
rs.resume ();
});
Finalmente, a transferência de dados do fluxo de dados somente leitura para o fluxo de dados somente de gravação é realizado e o controle do armazém à prova de explosão está incluído. Como existem muitos cenários de uso, como o programa de cópia de arquivo grande acima, o NodeJS fornece diretamente o método .pipe para fazer isso, e seu método de implementação interna é semelhante ao código acima.
Aqui está um processo mais completo de copiar arquivos:
A cópia do código é a seguinte:
var fs = requer ('fs'),
caminho = requer ('caminho'),
out = process.stdout;
var filepath = '/bb/bigbear.mkv';
var readstream = fs.creteReadstream (filepath);
var writeStream = fs.createwritSTream ('file.mkv');
var stat = fs.statsync (filepath);
var notalsize = stat.size;
var passEdLength = 0;
var lastSize = 0;
var startTime = date.now ();
readstream.on ('dados', função (chunk) {
passoudLength += chunk.length;
if (writestream.write (chunk) === false) {
readstream.pause ();
}
});
readstream.on ('end', function () {
writeStream.end ();
});
writestream.on ('drenagem', function () {
readstream.resume ();
});
setTimeout (function show () {
var % = math.ceil ((PassedLength / Totalsize) * 100);
var size = math.ceil (PassedLength / 1000000);
var diff = size - por último tamanho;
últimoSize = size;
out.clearline ();
out.cursorto (0);
out.write ('concluído' + size + 'mb,' + por cento + '%, velocidade:' + diff * 2 + 'mb/s');
if (PassedLength <Totalsize) {
setTimeout (show, 500);
} outro {
var endtime = date.now ();
console.log ();
console.log ('Quando compartilhado:' + (EndTime - StartTime) / 1000 + 'segundos.');
}
}, 500);
Você pode salvar o código acima como "copy.js". Experimento: Adicionamos um setTimeout recursivo (ou usamos diretamente o SetInterval) para ser um espectador.
Observe o progresso da conclusão a cada 500ms e escreva o tamanho, porcentagem e cópia completos para o console juntos. Quando a cópia é concluída, o tempo total é calculado.
Três, vamos resumir
(1) Entenda o conceito de fluxo.
(2) Proficiente no uso da API de fluxo relevante
(3) Preste atenção ao controle de detalhes, como: copiar arquivos grandes, usando a forma de "dados de chunk" para sharding.
(4), o uso do tubo
(5), enfatize um conceito novamente: uma conexão TCP é um fluxo legível e um fluxo gravável, enquanto uma conexão HTTP é diferente. Um objeto de solicitação HTTP é um fluxo legível, enquanto um objeto de resposta HTTP é um fluxo gravável.