7 dicas para novos usuários de node.js

Trabalho com node.js há quase um ano. Aqui estão minhas dicas para novos usuários do node.js.

Dê um nome

JavaScript permite objetos e funções sem nome. Geralmente, isso simplifica alguns trabalhos de nomenclatura e torna o lambda mais reduzido.

No entanto, função e objeto nomeados são para você depurar e criar perfis. Aqui, roubo uma foto de um artigo do Chrome DevTool :

Cenário

Muito legal, hein?

Sem referência anterior

O GC do JavaScript funciona como um contador de referência. O objeto pode ser liberado somente se não houver mais referência a ele.

Você pode ter clousres ou referência de objeto global um objeto para uso temperoray. Se sim, cancele a referência antes:

var some_var = new net.Server();
// other code...
var i_want_it_temperoray = some_var;
some_operation
(i_want_it_temperoray);
i_want_it_temperoray
= null; // derefernce
// other code...

Às vezes, se uma variável dentro do fechamento não pode ser liberada, o fechamento inteiro também não pode ser liberado pelo GC, o que leva a que todas as variáveis ​​não possam ser liberadas.

Existem algumas boas ferramentas para monitorar a memória, como heapdump, webkit-devtools-agent. Isso faz sentido que você deva usar mais funções nomeadas, conforme dito a seguir.

Sem cópia

O código no meu projeto muda muito rápido, algum código é copiado daqui para lá e reutilizado. Mas geralmente depois disso, algumas variáveis ​​que deveriam ser renomeadas ou já renomeadas são esquecidas, resultando em alguns comportamentos estranhos.

É bom digitar o código sozinho. Já que o IDE ou os editores podem ter a chance de verificar isso para você.

Cuidado ao envolver novos módulos

Existem três módulos do Node.js. Mas alguns deles realmente estão mortos. Node.js muda sua API frequentemente entre as versões principais. Módulo funciona em v0.8.x pode abortar em v0.10.x.

Antes de envolver um novo módulo, você deve verificar sua lista de pr ou lista de problemas, para garantir que não haja nenhum bug sério ou que ainda esteja em manutenção.

Use assíncrono ou promessa

Node.js é baseado em callbacks. É muito fácil escrever chamadas de função de retorno de chamada aninhadas. O retorno de chamada é bom para assíncrono, mas ruim para gerenciamento e manutenção de código e é difícil de depurar.

Se você começar a conectar o código com mais de 3 retornos de chamada aninhados, considere async.js ou algumas bibliotecas de promessa.

Esta é uma sequência simples de chamadas de função usando async.js:

async.auto([
'init_logger': function(done){
set_handlers_to_logger
(done);
},
'load_config': ['init_logger', function(done){
load_my_config
(done);
}],
'init_database': ['load_config', function(done){
connect_to_db_here
(done);
}],
// open_cache here doesn't require database opertion
'open_cache': ['load_config', function(done){
open_cache_here
(done);
}],
// warm_up usually fetch some data from database
// notice warm_up works only if 'init_database' AND 'open_cache' is done
'warm_up': ['init_database', 'open_cache', function(done){
fetch_some_data
(done);
}],
'init_routers': ['load_config', function(done){
install_routers
(done);
}],
'emit_out': ['warm_up', 'init_routers', function(done){
notify_others
(done);
}]
], function(err) {
if(err){
// handle possible err here
}
});

Não estou familiarizado com bibliotecas de promessa, como Q , mas acho que podemos ter chamadas legíveis semelhantes:

Q.nfcall(function init_logger(){
set_handlers_to_logger
();
})
.then(function load_config(){
load_my_config
();
})
.then(function init_database(){
connect_to_db_here
();
})
.then(function open_cache(){
open_cache_here
();
})
.then(function warm_up(){
fetch_some_data
();
})
.then(function init_routers(){
install_routers
();
})
.then(function emit_out(){
notify_others
();
})
.catch(function (error) {
// handle possible err here
})
.done();

Na maioria das vezes, a escolha é sua. Geralmente, async.js é muito fácil de iniciar, enquanto Q é muito mais flexível.

Por exemplo, as funções em async.js não são aninhadas, de modo que é um pouco mais difícil capturar variáveis, enquanto você pode aninhar thenclouses em Q ..

Eu planejava adicionar um exemplo para retornos de chamada aninhados diretos, mas realmente duvido que consiga consertar.

Você prefere CoffeeScript? Então você deve dar uma chance ao IcedCoffeeScript . IcedCoffeeScript fornece palavras-chave poderosas: awaite defer. Esses dois podem ser muito úteis quando você deseja uma sensação assíncrona no nível da linguagem. Basicamente, você pode ter quase todo o fluxo de controle assíncrono. Mas eu não sou um especialista em IcedCoffeeScript, sugiro que você verifique seu documento para obter detalhes e exemplos. Obrigado brettof86 por mencionar esta ideia brilhante.

O cliente pode estar muito lento

O Node.js é muito ideal às vezes, então pode ser muito fácil escrever um programa semelhante a um chat como abaixo:

var net = require('net');
var clientList = [];
var server = net.createServer(function(c) { //'connection' listener
console
.log('server connected');
clientList
.push(c);
c
.on('end', function() {
console
.log('server disconnected');
unpipe_all
(c, clientList);
remove_from
(c, clientList);
});
clientList
.forEach(function(item){
item
.pipe(c); // note this line
c
.pipe(item); // note this line
});
});
server
.listen(8124, function() { //'listening' listener
console
.log('server bound');
});
```javascript

The whole model is not that wrong, but you should notice that network of client is not that good as others. When use `pipe` here, lots of data will stay in memory until the client really receieve the data. Our assumption is client is fast, but that's only assumption!

One way to solve this is to have a delegate and make a conditional buffer mechanism internally, like below:

```javascript
Delegate delegate;
clientList
.forEach(function(item){
delegate
.append(item);
//internally, this delegate has an associated buffer as well as a disk file
//and use buffer when possible, or file if buffer is full.
});

Bem-vindo se você tiver outras idéias para resolver isso. Estou bastante aberto sobre isso;)

Emita quando terminar ou até mais tarde

A maioria dos objetos pequenos são construídos imediatamente, enquanto os maiores podem ser construídos de forma assíncrona.

Falando em construir qualquer objeto de forma assíncrona, é melhor você emitir um evento para notificar quando terminar. Se você seguir este, então você também iria notar uma declaração muito útil no documento de Node.js :

Isso é importante no desenvolvimento de APIs em que você deseja dar ao usuário a chance de atribuir manipuladores de eventos após a construção de um objeto, mas antes que qualquer I / O tenha ocorrido.

function MyThing(options) {
this.setupOptions(options);

process
.nextTick(function() {
this.startDoingStuff();
}.bind(this));
}

var thing = new MyThing();
thing
.getReadyForStuff();

// thing.startDoingStuff() gets called now, not before.

A maneira típica aqui é usar para enviar evento no construtor. Exemplo:process.nextTick

function SomeTCPServer(options) {
var self = this;
// other init work, and maybe async
process
.nextTick(function(){
self
.emit('ready');
});
}

// other code..
var server = new SomeTCPServer(ops);
server
.on('ready', function when_ready(){
// do something
});

Usando , tem a chance de ser vinculado antes da emissão do evento.process.nextTickwhen_ready

Talvez mais?

É o que posso concluir neste momento. Não tenho essa experiência no node, mas acho que isso pode ser útil para as pessoas que conhecem o node pela primeira vez 🙂 Sinta-se à vontade para comentar e apontar quaisquer falhas que fiz.