Showing preview only (227K chars total). Download the full file or copy to clipboard to get everything.
Repository: max-mapper/art-of-node
Branch: master
Commit: 71d0aba06053
Files: 13
Total size: 219.3 KB
Directory structure:
gitextract_g5wgeig8/
├── LICENSE.md
├── code/
│ ├── 1.js
│ ├── 2.js
│ ├── 3.js
│ ├── 4.js
│ └── number.txt
├── readme.es.md
├── readme.fr.md
├── readme.md
├── readme.pt-br.md
├── readme.ru.md
├── readme.zh-cn.md
└── readme.zh-tw.md
================================================
FILE CONTENTS
================================================
================================================
FILE: LICENSE.md
================================================
Creative Commons Share Alike (do whatever, just attribute me)
http://creativecommons.org/licenses/by-sa/2.0/
================================================
FILE: code/1.js
================================================
// cd code/
// node 1.js
var myNumber = 1
function addOne() { myNumber++ } // define the function
addOne() // run the function
console.log(myNumber) // logs out 2
================================================
FILE: code/2.js
================================================
// cd code/
// node 2.js
var fs = require('fs')
var myNumber = undefined // we dont know what the number is yet since it is stored in a file
function addOne() {
fs.readFile('./number.txt', function doneReading(err, fileContents) {
myNumber = parseInt(fileContents)
myNumber++
})
}
addOne()
console.log(myNumber) // logs out undefined
================================================
FILE: code/3.js
================================================
// cd code/
// node 3.js
var fs = require('fs')
var myNumber = undefined
function addOne(callback) {
fs.readFile('number.txt', function doneReading(err, fileContents) {
myNumber = parseInt(fileContents)
myNumber++
callback()
})
}
function logMyNumber() {
console.log(myNumber)
}
addOne(logMyNumber)
================================================
FILE: code/4.js
================================================
function takesOneSecond(callback) {
setTimeout(after, 1000)
function after() {
console.log('done with one, on to the next')
if (callback) callback()
}
}
a = takesOneSecond, b = takesOneSecond, c = takesOneSecond
a(function() {
b(function() {
c()
})
})
================================================
FILE: code/number.txt
================================================
1
================================================
FILE: readme.es.md
================================================
# El Arte de Node
## Una introducción a Node.js
Este documento está destinado a aquellos lectores que saben al menos un poco de esto:
- un lenguaje tipo script como JavaScript, Ruby, Python, Perl, etc. Si aun no eres programador entonces probablemente será más fácil empezar por leer [JavaScript for Cats](http://jsforcats.com/). :cat2:
- git y github. Éstas son herramientas colaborativas de código abierto usadas por las personas en la comunidad de Node para compartir módulos. Sólo necesitas conocer lo básico. Aquí hay tres tutoriales introductorios: [1](https://github.com/jlord/git-it-electron#readme), [2](http://zachbruggeman.me/github-for-cats/), [3](http://opensourcerer.diy.org/)
Este corto libro es un trabajo en progeso + No tengo trabajo en este momento (si tuviera no tendría el tiempo para escribir esto). Si te gusta este trabajo considera realizar una donación via [gittip](https://www.gittip.com/maxogden/) para poder escribir mucho más!
[](https://www.gittip.com/maxogden/)
## Tabla de contenidos
- [Entendiendo node](#entendiendo-node)
- [Módulos en el core](#mdulos-en-el-core)
- [Retrollamadas](#retrollamadas)
- [Events](#events) (not written yet)
- [Streams](#streams) (not written yet)
- [Modules and NPM](#modules) (not written yet)
- [Going with the grain](#going-with-the-grain)
- [Real-time apps](#realtime) (not written yet)
## Entendiendo node
Node.js es un proyecto de código abierto diseñado para ayudarte a escribir código JavaScript que se comunique con redes, archivos del sistema y otras E/S (entrada/salida, lectura/escritura) fuentes. Eso es! Node.js es simplemente una sencilla y estable plataforma E/S que anima a construir módulos sobre ella misma.
¿Cuáles son algunos de E/S? Aquí hay un diagrama de una aplicación que hice con Node y que muestra algunas fuentes de E/S:

Si no entiendes todos los elementos en el diagrama está bien. El punto es mostrar que un único proceso en Node (el hexágono en la mitad) puede actuar como agente entre todos los diferentes puntos finales de E/S (naranja y púrpura representan E/S).
Al construir uno de estos tipos de sistemas usualmente se presenta uno de estos casos:
- dificultad para programar pero con muy buenos y rápidos resultados (como escribir tus servidores web desde cero en C)
- Fácil de codificar pero no muy rápido/robusto (como cuando intentas subir un archivo de 5GB y tu servidor colapsa)
El objetivo de Node es proveer un balance entre: relativamente fácil de entender y usar, y lo suficientemente rápido para la mayoría de los casos.
Node no es ninguno de los siguientes:
- Un framework web (como Rails o Django, sin embargo puede ser usado para hacer tales cosas)
- Un lenguaje de programación (Node usa JavaScript pero no es en sí mismo un lenguaje)
En su lugar, Node es algo en la mitad:
- Diseñado para ser simple y por lo tanto relativamente fácil de entender y usar
- Útil para programas basados en E/S que necesitan ser rápidos y/o manejar muchas conecciones
A un nivel más bajo, Node puede ser descrito como una herramienta para escribir dos grandes tipos de programas:
- Programas de red que usen los protocolos de la web: HTTP, TCP, UDP, DNS and SSL
- Programas que lean y escriban información al sistema de archivos o a los procesos/memoria local
¿Qué es un "programa basado en E/S"? Aquí hay alguna fuentes comunes de E/S:
- Bases de datos (MySQL, PostgreSQL, MongoDB, Redis, CouchDB)
- APIs (Twitter, Facebook, Apple Push Notifications)
- Conecciones HTTP/WebSocket (desde usuarios de una aplicación web)
- Archivos (editor de imágenes, editor de videos, radio por internet)
Node procesa E/S en una forma llamada [asíncrona](http://en.wikipedia.org/wiki/Asynchronous_I/O) el cual le permite manejar muchas cosas diferentes simultáneamente. Por ejemplo, si vas a un restaurante de comida rápida y ordenas una hamburguesa ellos tomarán tu orden inmediatamente y te harán esperar hasta que tu hamburguesa esté lista. Mientras tanto ellos pueden tomar otras órdenes y empezar a preparar hamburguesas para otras personas. Imagina si tuvieras que esperar en la caja registradora por tu hamburguesa, bloqueando a todas las otras personas en la fila para ordenar, mientras preparan tu hamburguesa! Esto es llamado **bloqueo de E/S** porque toda E/S (preparación de hamburguesas) suceden una vez al tiempo. Node, por otro lado, es de **no-bloque**, que significa que puede preparar muchas hamburguesas al tiempo.
Aquí hay algunas cosas divertidas hechas de manera fácil con Node gracias a su naturaleza de no-bloque:
- Control [volando quadcopters](http://nodecopter.com)
- Escribir bots para chat IRC
- Crear [robots bípedos](http://www.youtube.com/watch?v=jf-cEB3U2UQ)
## Módulos en el core
Primero que todo recomiendo tener instalado Node en tu computadora. La forma más fácil es visitar [nodejs.org](http://nodejs.org) y dar click en `Install`.
Node tiene un pequeño grupo de módulos en el core (comunmente referenciados como 'core de node') los cuales son presentados como la API pública que tienen por objeto el escribir programas con ellos. Para trabajar con sistemas de archivos está el módulo `fs` y para redes existen módulos como `net` (TCP), `http`, `dgram` (UDP).
Adicionalmente a los módulos `fs` y de redes, hay otros módulos base en el core de node. Existe un módulo para resolver consultas DNS asincronamente llamado `dns`, un módulo para obtener información específica del SO como el directorio temporal, llamado `os`, un módulo para asignar pedazos binarios de memoria llamado `buffer`, algunos módulos para parsear urls y caminos (`url`, `querystring`, `path`), etc. La mayoría si no todos los módulos en el core de Node, están para soportar los casos de uso principales de Node: Escribir programas rápidos que se comuniquen con sistemas de archivos o redes.
Node maneja E/S con: callbacks, eventos, streams (flujos) y módulos. Si aprendes cómo trabajan esos cuatro elementos entonces serás capaz de ir dentro de cualquier módulo en el core de Node y entender básicamente sobre cómo interactuar con él.
## Retrollamadas
Este es el tema más importante para entender si quieres entender cómo utilizar node. Casi todo en node utiliza retrollamadas. No fueron inventadas por node, y son una forma particularmente útil para utilizar las funciones en JavaScript.
Las retrollamadas son funciones que se ejecutan de forma asíncrona, o en un momento posterior. En lugar de leer el código de arriba a abajo, programas asincrónicos pueden ejecutar diferentes funciones en diferentes momentos basado en el orden y la velocidad que ocurren las funciones que leen el sistema de archivo o los pedidos de http.
Determinando si una función es asíncrona o no puede crear confusión ya que depende mucho en el contexto donde se presenta. Aquí sigue un ejemplo simple de una función sincrónica:
```js
var miNumero = 1
function agregaUno() { miNumeror++ } // define la función
agregaUno() // ejecuta la función
console.log(miNumero) // registra 2
```
++++++++++++++++++++++++Continue Translation+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
The code here defines a function and then on the next line calls that function, without waiting for anything. When the function is called it immediately adds 1 to the number, so we can expect that after we call the function the number should be 2.
Let's suppose that we want to instead store our number in a file called `number.txt`:
```js
var fs = require('fs') // require is a special function provided by node
var myNumber = undefined // we dont know what the number is yet since it is stored in a file
function addOne() {
fs.readFile('./number.txt', function doneReading(err, fileContents) {
myNumber = parseInt(fileContents)
myNumber++
})
}
addOne()
console.log(myNumber) // logs out undefined
```
Why do we get `undefined` when we log out the number this time? In this code we use the `fs.readFile` method, which happens to be an asynchronous method. Usually things that have to talk to hard drives or networks will be asynchronous. If they just have to access things in memory or do some work on the CPU they will be synchronous. The reason for this is that I/O is reallyyy reallyyy sloowwww. A ballpark figure would be that talking to a hard drive is about 100,000 times slower than talking to memory (RAM).
When we run this program all of the functions are immediately defined, but they don't all execute immediately. This is a fundamental thing to understand about async programming. When `addOne` is called it kicks off a `readFile` and then moves on to the next thing that is ready to execute. If there is nothing to execute node will either wait for pending fs/network operations to finish or it will stop running and exit to the command line.
When `readFile` is done reading the file (this may take anywhere from milliseconds to seconds to minutes depending on how fast the hard drive is) it will run the `doneReading` function and give it an error (if there was an error) and the file contents.
The reason we got `undefined` above is that nowhere in our code exists logic that tells the `console.log` statement to wait until the `readFile` statement finishes before it prints out the number.
If you have some code that you want to be able to execute over and over again or at a later time the first step is to put that code inside a function. Then you can call the function whenever you want to run your code. It helps to give your functions descriptive names.
Callbacks are just functions that get executed at some later time. The key to understanding callbacks is to realize that they are used when you don't know **when** some async operation will complete, but you do know **where** the operation will complete — the last line of the async function! The top-to-bottom order that you declare callbacks does not necessarily matter, only the logical/hierarchical nesting of them. First you split your code up into functions, and then use callbacks to declare if one function depends on another function finishing.
The `fs.readFile` method is provided by node, is asynchronous and happens to take a long time to finish. Consider what it does: it has to go to the operating system, which in turn has to go to the file system, which lives on a hard drive that may or may not be spinning at thousands of revolutions per minute. Then it has to use a laser to read data and send it back up through the layers back into your javascript program. You give `readFile` a function (known as a callback) that it will call after it has retrieved the data from the file system. It puts the data it retrieved into a javascript variable and calls your function (callback) with that variable, in this case the variable is called `fileContents` because it contains the contents of the file that was read.
Think of the restaurant example at the beginning of this tutorial. At many restaurants you get a number to put on your table while you wait for your food. These are a lot like callbacks. They tell the server what to do after your cheeseburger is done.
Let's put our `console.log` statement into a function and pass it in as a callback.
```js
var fs = require('fs')
var myNumber = undefined
function addOne(callback) {
fs.readFile('./number.txt', function doneReading(err, fileContents) {
myNumber = parseInt(fileContents)
myNumber++
callback()
}
}
function logMyNumber() {
console.log(myNumber)
}
addOne(logMyNumber)
```
Now the `logMyNumber` function can get passed in an argument that will become the `callback` variable inside the `addOne` function. After `readFile` is done the `callback` variable will be invoked (`callback()`). Only functions can be invoked, so if you pass in anything other than a function it will cause an error.
When a function get invoked in javascript the code inside that function will immediately get executed. In this case our log statement will execute since `callback` is actually `logMyNumber`. Remember, just because you *define* a function it doesn't mean it will execute. You have to *invoke* a function for that to happen.
To break down this example even more, here is a timeline of events that happen when we run this program:
- 1: the code is parsed, which means if there are any syntax errors they would make the program break.
- 2: `addOne` gets invoked, getting passed in the `logMyNumber` function as `callback`, which is what we want to be called when `addOne` is complete. This immediately causes the asynchronous `fs.readFile` function to kick off. This part of the program takes a while to finish.
- 3: with nothing to do, node idles for a bit as it waits for `readFile` to finish
- 4: `readFile` finishes and calls its callback, `doneReading`, which then in turn increments the number and then immediately invokes the function that `addOne` passed in (its callback), `logMyNumber`.
Perhaps the most confusing part of programming with callbacks is how functions are just objects that be stored in variables and passed around with different names. Giving simple and descriptive names to your variables is important in making your code readable by others. Generally speaking in node programs when you see a variable like `callback` or `cb` you can assume it is a function.
You may have heard the terms 'evented programming' or 'event loop'. They refer to the way that `readFile` is implemented. Node first dispatches the `readFile` operation and then waits for `readFile` to send it an event that it has completed. While it is waiting node can go check on other things. Inside node there is a list of things that are dispatched but haven't reported back yet, so node loops over the list again and again checking to see if they are finished. After they finished they get 'processed', e.g. any callbacks that depended on them finishing will get invoked.
Here is a pseudocode version of the above example:
```js
function addOne(thenRunThisFunction) {
waitAMinuteAsync(function waitedAMinute() {
thenRunThisFunction()
})
}
addOne(function thisGetsRunAfterAddOneFinishes() {})
```
Imagine you had 3 async functions `a`, `b` and `c`. Each one takes 1 minute to run and after it finishes it calls a callback (that gets passed in the first argument). If you wanted to tell node 'start running a, then run b after a finishes, and then run c after b finishes' it would look like this:
```js
a(function() {
b(function() {
c()
})
})
```
When this code gets executed, `a` will immediately start running, then a minute later it will finish and call `b`, then a minute later it will finish and call `c` and finally 3 minutes later node will stop running since there would be nothing more to do. There are definitely more elegant ways to write the above example, but the point is that if you have code that has to wait for some other async code to finish then you express that dependency by putting your code in functions that get passed around as callbacks.
The design of node requires you to think non-linearly. Consider this list of operations:
```
read a file
process that file
```
If you were to naively turn this into pseudocode you would end up with this:
```
var file = readFile()
processFile(file)
```
This kind of linear (step-by-step, in order) code is isn't the way that node works. If this code were to get executed then `readFile` and `processFile` would both get executed at the same exact time. This doesn't make sense since `readFile` will take a while to complete. Instead you need to express that `processFile` depends on `readFile` finishing. This is exactly what callbacks are for! And because of the way that JavaScript works you can write this dependency many different ways:
```js
var fs = require('fs')
fs.readFile('movie.mp4', finishedReading)
function finishedReading(error, movieData) {
if (error) return console.error(error)
// do something with the movieData
}
```
But you could also structure your code like this and it would still work:
```js
var fs = require('fs')
function finishedReading(error, movieData) {
if (error) return console.error(error)
// do something with the movieData
}
fs.readFile('movie.mp4', finishedReading)
```
Or even like this:
```js
var fs = require('fs')
fs.readFile('movie.mp4', function finishedReading(error, movieData) {
if (error) return console.error(error)
// do something with the movieData
})
```
## Events
In node if you require the [events](http://nodejs.org/api/events.html) module you can use the so-called 'event emitter' that node itself uses for all of its APIs that emit things.
Events are a common pattern in programming, known more widely as the ['observer pattern'](http://en.wikipedia.org/wiki/Observer_pattern) or 'pub/sub' (publish/subscribe). Whereas callbacks are a one-to-one relationship between the thing waiting for the callback and the thing calling the callback, events are the same exact pattern except with a many-to-many API.
Here are few common use cases for using events instead of plain callbacks:
- Chat room where you want to broadcast messages to many listeners
- Game server that needs to know when new players connect, disconnect, move, shoot and jump
- Database connector that might need to know when the database connection opens, closes or sends an error
If we were trying to write a module that connects to a chat server using only callbacks it would look like this:
```js
var chatClient = require('my-chat-client')
function onConnect() {
// have the UI show we are connected
}
function onConnectionError(error) {
// show error to the user
}
function onDisconnect() {
// tell user that they have been disconnected
}
function onMessage(message) {
// show the chat room message in the UI
}
chatClient.connect(
'http://mychatserver.com',
onConnect,
onConnectionError,
onDisconnect,
onMessage
)
```
As you can see this is really cumbersome because of all of the functions that you have to pass in a specific order to the `.connect` function. Writing this with events would look like this:
```js
var chatClient = require('my-chat-client').connect()
chatClient.on('connect', function() {
// have the UI show we are connected
})
chatClient.on('connectionError', function() {
// show error to the user
})
chatClient.on('disconnect', function() {
// tell user that they have been disconnected
})
chatClient.on('message', function() {
// show the chat room message in the UI
})
```
This approach is similar to the pure-callback approach but introduces the `.on` method, which subscribes a callback to an event. This means you can choose which events you want to subscribe to from the `chatClient`. You can also subscribe to the same event multiple times with different callbacks:
```js
var chatClient = require('my-chat-client').connect()
chatClient.on('message', logMessage)
chatClient.on('message', storeMessage)
function logMessage(message) {
console.log(message)
}
function storeMessage(message) {
myDatabase.save(message)
}
```
MORE EVENTS CONTENT TODO
## Streams
Early on in the project the file system and network APIs had their own separate patterns for dealing with streaming I/O. For example, files in a file system have things called 'file descriptors' so the `fs` module had to have extra logic to keep track of these things whereas the network modules didn't have such a concept. Despite minor differences in semantics like these, at a fundamental level both groups of code were duplicating a lot of functionality when it came to reading data in and out. The team working on node realized that it would be confusing to have to learn two sets of semantics to essentially do the same thing so they made a new API called the `Stream` and made all the network and file system code use it.
The whole point of node is to make it easy to deal with file systems and networks so it made sense to have one pattern that was used everywhere. The good news is that most of the patterns like these (there are only a few anyway) have been figured out at this point and it is very unlikely that node will change that much in the future.
THE REST IS TODO, in the meantime read the [streams handbook](https://github.com/substack/stream-handbook#introduction)
## Modules
TODO
## Going with the grain
Like any good tool, node is best suited for a certain set of use cases. For example: Rails, the popular web framework, is great for modeling complex [business logic](http://en.wikipedia.org/wiki/Business_logic), e.g. using code to represent real life business objects like accounts, loan, itineraries, and inventories. While it is technically possible to do the same type of thing using node, there would be definite drawbacks since node is designed for solving I/O problems and it doesn't know much about 'business logic'. Each tool focuses on different problems. Hopefully this guide will help you gain an intuitive understanding of the strengths of node so that you know when it can be useful to you.
### What is outside of node's scope?
Fundamentally node is just a tool used for managing I/O across file systems and networks, and it leaves other more fancy functionality up to third party modules. Here are some things that are outside the scope of node:
#### Web frameworks
There are a number of web frameworks built on top of node (framework meaning a bundle of solutions that attempts to address some high level problem like modeling business logic), but node is not a web framework. Web frameworks that are written using node don't always make the same kind of decisions about adding complexity, abstractions and tradeoffs that node does and may have other priorities.
#### Language syntax
Node uses JavaScript and doesn't change anything about it. Felix Geisendörfer has a pretty good write-up of the 'node style' [here](https://github.com/felixge/node-style-guide).
#### Language abstraction
When possible node will use the simplest possible way of accomplishing something. The 'fancier' you make your JavaScript the more complexity and tradeoffs you introduce. Programming is hard, especially in JS where there are 1000 solutions to every problem! It is for this reason that node tries to always pick the simplest, most universal option. If you are solving a problem that calls for a complex solution and you are unsatisfied with the 'vanilla JS solutions' that node implements, you are free to solve it inside your app or module using whichever abstractions you prefer.
A great example of this is node's use of callbacks. Early on node experimented with a feature called 'promises' that added a number of features to make async code appear more linear. It was taken out of node core for a few reasons:
- they are more complex than callbacks
- they can be implemented in userland (distributed on npm as third party modules)
Consider one of the most universal and basic things that node does: reading a file. When you read a file you want to know when errors happen, like when your hard drive dies in the middle of your read. If node had promises everyone would have to branch their code like this:
```js
fs.readFile('movie.mp4')
.then(function(data) {
// do stuff with data
})
.error(function(error) {
// handle error
})
```
This adds complexity, and not everyone wants that. Instead of two separate functions node just uses a single callback function. Here are the rules:
- When there is no error pass null as the first argument
- When there is an error, pass it as the first argument
- The rest of the arguments can be used for anything (usually data or responses since most stuff in node is reading or writing things)
Hence, the node callback style:
```js
fs.readFile('movie.mp4', function(err, data) {
// handle error, do stuff with data
})
```
#### Threads/fibers/non-event-based concurrency solutions
Note: If you don't know what these things mean then you will likely have an easier time learning node, since unlearning things is just as much work as learning things.
Node uses threads internally to make things fast but doesn't expose them to the user. If you are a technical user wondering why node is designed this way then you should 100% read about [the design of libuv](http://nikhilm.github.com/uvbook/), the C++ I/O layer that node is built on top of.
## Real-time apps
TODO - this section will have a non-contrived, functioning application with a web UI whose architecture will be dissected and discussed.
## License

Creative Commons Attribution License (do whatever, just attribute me)
http://creativecommons.org/licenses/by/2.0/
Donate icon is from the [http://thenounproject.com/noun/donate/#icon-No285](Noun Project)
================================================
FILE: readme.fr.md
================================================
# The Art of Node
## Une introduction à Node.js
Si vous souhaitez découvrir Node et que les connaissances énoncées ci-après vous sont familières, ce document est fait pour vous :
- Un langage de script, tel que JavaScript, Ruby, Python, Perl, etc. Si vous n'êtes pas programmeur, vous préfèrerez sans doute précéder cette lecture par la découverte de [JavaScript for Cats](http://jsforcats.com/). :cat2:
- Git & Github qui sont les outils de collaboration privilégiés par la communauté. Rassurez-vous, pas besoin d'être expert, quelques connaissances basiques suffiront. Au besoin, voici trois superbes tutos pour bien démarrer avec git : [1](https://github.com/jlord/git-it-electron#readme), [2](http://ericsteinborn.com/github-for-cats/#/), [3](http://opensourcerer.diy.org/)
Ce court livre est une oeuvre en cours de réalisation. Si vous l'aimez, **donnez-moi un dollar** via
[gittip](https://www.gittip.com/maxogden/) pour me permettre d'y consacrer du temps !
[](https://www.gittip.com/maxogden/)
## Sommaire
- [Apprentissage Interactif de Node](#apprentissage-interactif-de-node)
- [Comprendre Node](#comprendre-node)
- [Modules de base](#modules-de-base)
- [Callbacks](#callbacks)
- [Evenements](#evenements)
- [Flux](#flux)
- [Modules & npm](#modules)
- [Développement côté client avec npm](#developpez-cote-client-avec-npm)
- [Suivez le mouvement !](#suivez-le-mouvement)
## Apprentissage Interactif de Node
Par expérience, j'ai appris que la simple lecture d'un guide ne se suffit pas à elle-même. Gardez votre éditeur de texte favoris sous la main et écrivez du node en parallèle ! Apprendre en codant est le meilleur moyen d'intégrer les concepts que vous lirez.
### NodeSchool.io
[NodeSchool.io](http://nodeschool.io/) est une série d'ateliers opensource et gratuits qui vous enseignerons les principes de Node.js, et plus encore pour les curieux !
[Learn You The Node.js](https://github.com/rvagg/learnyounode#learn-you-the-nodejs-for-much-win) est le cours introductif aux ateliers NodeSchool.io. Il met en scène les principaux cas d'utilisation de Node.js. Il est conçu pour être utilisé directement en ligne de commande.
[](https://github.com/rvagg/learnyounode#learn-you-the-nodejs-for-much-win)
Installez-le avec npm:
```
# install
npm install learnyounode -g
# start the menu
learnyounode
```
## Comprendre Node
Node.js est un projet opensource conçu pour vous aider à écrire des programmes JavaScript qui interagissent avec des réseaux, des Filesystems ou toute autre source d'I/O (entrée/sortie, lecture/ecriture). Et c'est tout! Node n'est qu'une plateforme simple et stable qui vous encourage à construire des modules par dessus.
Avec quelques exemples, tout sera plus clair. Ci-après le diagramme d'une application que j'ai réalisé avec Node et qui présente de nombreuses sources d'I/O:

Rassurez-vous, vous n'avez pas besoin de tout comprendre à ce graphe. Le but est de vous montrer qu'un simple processus node (l'hexagone au centre) peut agir comme un hub entre les différentes sources d'I/O (en orange et violet sur le diagramme).
Usuellement, produire ce type de système induit deux conséquences probables:
- D'excellentes performances a l'exécution, mais aux prix de difficultés dans l'écriture (comme partir de zéro pour écrire un serveur web en C)
- Une simplicité d'écriture, mais de faibles performances, ou un manque de robustesse (comme quand quelqu'un essaye d'envoyer un fichier de 5Go sur votre serveur et qu'il crash)
L'objectif poursuivit par Node est de trouver l'équilibre entre ces deux situations : Être accessible tout en offrant des performances optimales.
Attention, Node n'est ni :
- Un framework web (comme Rails ou Django, même s'il peut être utilisé pour produire ce genre de choses)
- Un langage de programmation (Il est basé sur JavaScript mais node n'est pas son propre langage)
Au lieu de cela, Node se situe quelque part au milieu. On peut dire qu'il est à la fois :
- Conçu pour être simple et donc relative facile à comprendre et utiliser
- Adapté aux programmes fondés sur des I/O, nécessitants rapidité et capacité à gérer de nombreuses connections
A bas niveau, Node peut se décrire comme un outil permettant l'écriture de deux types de programmes majeurs :
- Les programmes de Réseaux qui utilisent les protocoles du web: HTTP, TCP, UDP, DNS and SSL
- Les programmes qui lisent et écrivent des données dans les filesystem ou dans les processus locaux ou en mémoire.
Qu'est-ce qu'un programme "fondé sur des I/O" ? Voici quelques exemples de sources:
- Bases de données (e.g. MySQL, PostgreSQL, MongoDB, Redis, CouchDB)
- APIs (e.g. Twitter, Facebook, Notifications Push Apple)
- HTTP/connections WebSocket (des utilisateurs d'une application web)
- Fichiers (redimensionnement d'images, editeur video, radio internet)
Node gère les I/O de manière [asynchrone](http://en.wikipedia.org/wiki/Asynchronous_I/O) ce qui le rend très efficace dans la gestion de processus simultanés. Prenons un exemple: si vous commander un cheeseburger dans un fast-food, ils prendront votre commande et vous feront patienter le temps que votre plat soit prêt. Pendant ce temps, ils prendront les commandes des autres clients et n'auront aucun mal à démarrer la cuissons de leur cheeseburger en parralèle. Maintenant imaginez un peu si vous deviez attendre votre sandwich au comptoire, empêchant tous les clients derrière vous de commander jusqu'à ce que votre produit soit prêt ! On appelle cela l'**I/O Bloquante** car toutes les I/O se produisent l'une après l'autre. Node, à contrario, est **non-bloquante**, ce qui signifie qu'il peut cuire plusieurs cheeseburgers à la fois !
Quelques exemples amusants de choses permises par la nature non-bloquante de Node :
- Contrôler des [quadricopters volants](http://nodecopter.com)
- Ecrire des bots IRC
- Créer des [robots marcheurs bipèdes](http://www.youtube.com/watch?v=jf-cEB3U2UQ)
## Modules de base
Pour commencer, je vous suggère d'installer Node sur votre machine. Le plus simple est de vous rendre sur [nodejs.org](http://nodejs.org) et de cliquer sur 'Install'.
Node possède nativement un petit groupe de modules (qui réponds communément au nom de 'Node core' - 'Coeur de Node') qui sont présenté en tant qu'API publique, et avec lesquels nous sommes censés écrire nos programmes. Pour travailler avec un file system, il y a le module 'fs', et pour les réseaux, les modules comme `net` (TCP), `http`, `dgram` (UDP).
En sus de `fs` et des modules de réseau, le Coeur de Node propose d'autres modules de base. Il existe un module pour gérer les requêtesDNS de manière asynchrones nommé `dns`, un autre pour récupérer les informations spécifiques à l'OS comme la path du tmpdir nommé `os`, encore un pour allouer des morceaux de mémoire nommé `buffer`, d'autres pour parser les url et les paths (`url`, `querystring`, `path`), etc. La plus part, sinon tous, sont là pour gérer le principal cas d'utilisation de node: Ecrire rapidement des programmes qui parlent aux files systems et aux réseaux.
Node possède plusieurs cordes à son arc pour gérer les 'I/O: des callbacks, des évènements, des streams - 'flux' et des modules. Si vous arrivez à apprendre comment ces quatre structures fonctionnent, alors vous serez capable d'aller dans n'importe lequel des module core de Node, et de comprendre comment vous interfacer avec eux.
## Callbacks
Voilà le sujet le plus important si vous voulez comprendre comment utiliser node. On retrouve les callbacks à peu près partout dans Node. Ils n'ont pas été inventés par node cependant, ils font simplement parti intégrante de JavaScript.
Les Callbacks sont des fonctions qui s'exécutent de manière asynchrone ou plus tard dans le temps. Au lieu de lire le code de haut en bas de manière procédurale, les programmes asynchrones peuvent exécuter différentes fonctions à différents moments. Cet ordre sera définit en fonction de l'ordre et de la vitesse des précédents appels, comme les requetes HTTP ou bien encore la lecture du file system.
Cette différence peut entrainer des confusions, car déterminer si une fonction est asynchrone our non dépend beaucoup de son contexte. Voici un exemple synchrone, ce qui signifie que que vous pouvez lire ce code de haut en bas comme un livre:
```js
var myNumber = 1
function addOne() { myNumber++ } // define the function
addOne() // run the function
console.log(myNumber) // logs out 2
```
Ce code définit une fonction, puis appel cette fonction, sans attendre quoi que ce soit. Quand la fonction est appelé, elle ajoute immédiatement 1 aux nombre. On peut donc s'attendre à ce qu'après l'appel de cette fonction, le nombre soit égal à 2. De manière assez basique donc, le code synchrone s'exécute de haut en bas.
Node en revanche, utilise essentiellement du code asynchrone. Utilisons Node pour lire notre nombre depuis un fichier appelé `number.txt`:
```js
var fs = require('fs') // require is a special function provided by node
var myNumber = undefined // we don't know what the number is yet since it is stored in a file
function addOne() {
fs.readFile('number.txt', function doneReading(err, fileContents) {
myNumber = parseInt(fileContents)
myNumber++
})
}
addOne()
console.log(myNumber) // logs out undefined -- this line gets run before readFile is done
```
Pourquoi obtenons nous `undefined` quand nous affichons le chiffre cette fois ci ? Dans ce code, nous utilisons la méthode`fs.readFile`, qui est une méthode asynchrone. Tout ce qui doit parler à un disque dur ou à un réseau aura tendance à être asynchrone. Si leur objectif est simplement d'accéder à la mémoire, ou travailler avec le processeur, alors ils seront synchrone. La raison est que l'I/O est effroyablement lent! En guise d'illustration, dites vous que parler avec un disque dur est environ 100,000 fois plus lent qu'une communication avec la mémoire(e.g. RAM).
Quand nous lançons ce programme, toutes ses fonctions sont immédiatement définies, mais elles n'ont pas besoin de s'exécuter immédiatement. C'est un élément fondamental à comprendre en programmation asynchrone. Quand `addOne` est appelé, il démarre `readFile` et enchaine avec le prochain élément prêt à être exécuté. S'il n'y a rien dans la file d'attente, Node attendra les opérations fs/réseau en attente pour terminer, ou il s'arrêtera simplement de tourner et sortira sur la ligne de commande.
Quand `readFile` aura terminé de lire le fichier (cela peut prendre entre quelques millisecondes et plusieurs minutes, en fonction de la vitesse du disque dur) il lancera la fonction `doneReading`, puis lui donnera une erreur (s'il y en a une) ainsi que le contenu du fichier.
La raison pour laquelle nous obtenons `undefined` ci-dessus est qu'il n'existe aucune logique dans notre code pour dire à notre `console.log` d'attendre que le `readFile` ait terminé avant de sortir notre chiffre.
Si vous avez du code que vous voulez pouvoir exécuter encore et encore, ou simplement plus tard, la première étape consiste à encapsuler ce code dans une fonction. Ensuite, vous pouvez indiquer à votre fonction le moment où elle devra l'exécuter. Bien évidemment, donner des noms descriptifs et verbeux à vos fonction aidera grandement.
Les Callbacks ne sont que des fonctions qui s'exécutent plus tard. La clef pour comprendre les callbacks est de réaliser que vous ne savez pas **quand** une opération asynchrone sera terminée, mais vous savez **où** cette opération doit se compléter - la dernière ligne de votre fonction asynchrone ! L'ordre haut-en-bas de déclaration de vos callbacks n'a pas d'importance, seul l'encapsulation logique compte. Commencez par découper votre code en fonction, puis utilisez vos callbacks pour déclarer qu'une fonction requiert qu'une autre se termine.
La méthode `fs.readFile` fournie par node est asynchrone et il se trouve qu'elle prend beaucoup de temps pour se terminer. Mettez-vous à sa place: elle doit aller interroger l'OS, qui à son tour doit se renseigner auprès du file système, qui vit sur le disque dur, qui peut ne pas en trainer de tourner à des miliers de tours par minute. Ensuite il doit utiliser un laser pour lire une donnée, puis la renvoyer à travers toutes les strates successives de votre programme JavaScript. Vous donnez donc à `readFile` une fonction (aussi appelé callback) qu'il appellera une fois qu'il aura récupéré les données de votre file system. Il placera les données qu'il a récupéré dans une variable JavaScript et appellera votre callback avec cette variable. Dans ce cas, la variable est nommé `fileContents` car elle détient le contenu du fichier qui a été lu.
Reprenez l'exemple du restaurant cité au début de ce tuto. Très souvent, vous trouverez dans les restaurant des numéros à poser sur votre table pendant que vous patientez. Ces numéros sont comme des callbacks. Ils indiquent au serveur ce qu'ils doivent faire une fois que votre sandwich est prêt.
Plaçons maintenant notre `console.log` dans une fonction et passons le en callback.
```js
var fs = require('fs')
var myNumber = undefined
function addOne(callback) {
fs.readFile('number.txt', function doneReading(err, fileContents) {
myNumber = parseInt(fileContents)
myNumber++
callback()
})
}
function logMyNumber() {
console.log(myNumber)
}
addOne(logMyNumber)
```
La fonction `logMyNumber` peut désormais être passée en argument qui deviendra la variable de `callback` dans la fonction `addOne`. Une fois que `readFile` en a terminé, la variable `callback` sera invoquée (`callback()`). Seules les fonctions peuvent être invoquées, donc si vous passez n'importe quoi d'autre qu'une fonction, il en résultera une erreur.
Quand une fonction est invoquée en JavaScript, le code qu'elle renferme est immédiatement exécuté. Dans notre cas, notre console log s'exécutera puisque `callback` est `logMyNumber`. Rappelez-vous, le simple fait de *define* une fonction ne signifie pas qu'elle s'exécutera. Pour ce faire, vous devez *invoke* une fonction.
Pour aller encore plus loin avec cet exemple, voici une liste chronique des évènements qui se produisent à l'éxécution de ce code:
- 1: Le code est parsé, ce qui signifique qu'une quelconque erreur syntaxique casserait le programme. Durant cette phase initiale, il y a 4 choses qui sont définies: `fs`, `myNumber`, `addOne`, and `logMyNumber`. Notez qu'elles sont simplement définies. Aucune fonction n'a encore été invoquée ou appelée pour le moment.
- 2: Quand la dernière ligne de notre programme est exécutée `addOne` est invoqué, puis est passé dans la fonction `logMyNumber` comme 'callback', ce qui est bien ce que nous demandons quand `addOne` est terminé. Cela entraine immédiatement le démarrage de la fonction asynchrone `fs.readFile`. Cette partie du programme prend un peu de temps à se terminer.
- 3: Puisqu'il n'a rien à faire, Node patiente pendant que `readFile` se termine. S'il y avait une quelconque autre tache à réaliser, Node serait disponible pour faire le boulot.
- 4: `readFile` se termine et appelle son callback, `doneReading`, qui à son tour incrémente le nombre et invoque immédiatement la fonction qu'`addOne` a passé, `logMyNumber` (son callback).
La chose la plus troublante quand on programme avec des callbacks est probablement le fait que les fonctions sont de simples objets, encapsulables dans des variables et que l'on peut passer n'importe où avec des noms différents. Affecter des noms simples et descriptifs à vos variables est primordiale pour rendre votre code lisible pour les autres comme pour vous-même. D'une manière générale, si vous voyez une variable comme `callback` ou `cb` vous pouvez partir du principe qu'il s'agit d'une fonction.
Vous avez peut-être entendu les termes de 'evented programming' (programmation évènementielle) ou 'event loop' (boucle d'évènement). Ils se réfèrent à la manière dont `readFile` est implémenté. Node dispatch d'abord les opérations `readFile` puis attends que `readFile` envoi un évènement qu'il a clôturé.
Pendant qu'il patiente, Node peut tranquillement s'affairer ailleurs. Pour s'y retrouver, Node maintient une liste de tâches qui ont été dispatchées mais qui n'ont pas encore reçu de feedback, et boucle dessus indéfiniment jusqu'à ce que l'une d'entre elle soit terminée. Une fois chose faite, Node invoque les éventuels callbacks qui lui sont rattachés.
Voila une version de l'exemple précédent en pseudocode:
```js
function addOne(thenRunThisFunction) {
waitAMinuteAsync(function waitedAMinute() {
thenRunThisFunction()
})
}
addOne(function thisGetsRunAfterAddOneFinishes() {})
```
Imaginez que vous avez 3 fonctions asynchrones `a`, `b` et `c`. Chacune d'entre elle prend environ 1 minute a être complétée puis lance un callback (qui se voit passé en premier argument). Si vous vouliez dire à node 'lance a, puis b une fois que a est terminé, puis c une fois que b est terminé', cela ressemblerait à cela :
```js
a(function() {
b(function() {
c()
})
})
```
Quand ce code est exécuté, `a` démarrera immédiatement, puis une minute plus tard il appellera `b`, qui une minute plus tard lancera `c`. Au bout de 3 minutes, node s'arrêtera puisqu'il n'y aura plus rien à faire. Bien évidemment, il existe des méthodes plus élégantes pour écrire le code ci-dessus, mais le but est de montrer que si vous avez du code qui doit attendre un autre code asynchrone pour s'exécuter, alors il faut exprimer cette dépendance en disposant votre code dans une fonction qui sera alors passé comme callback.
Le design de node requière un mode de pensé non-linéaire. Considérez donc cette liste d'opérations:
```
read a file
process that file
```
Si vous transformiez cela en pseudocode vous obtiendriez ceci:
```
var file = readFile()
processFile(file)
```
Ce type de code non-linéaire (étape par étape, dans l'ordre) n'est pas la manière dont Node fonctionne. Si ce code devait être exécuté, alors `readFile` et `processFile` devraient être lancés au même moment. Cela n'aurait aucun sens puisque `readFile` mettra du temps à se terminer. A la place, vous devez signifier que `processFile` dépend de `readFile`. C'est exactement à cela que servent les callbacks ! Et parce que javascript fonctionne ainsi, vous pourrez écrire cette dépendance de plusieurs manières:
```js
var fs = require('fs')
fs.readFile('movie.mp4', finishedReading)
function finishedReading(error, movieData) {
if (error) return console.error(error)
// do something with the movieData
}
```
Mais vous pourriez aussi structurer votre code de cette façon et il fonctionnerait toujours:
```js
var fs = require('fs')
function finishedReading(error, movieData) {
if (error) return console.error(error)
// do something with the movieData
}
fs.readFile('movie.mp4', finishedReading)
```
Ou même comme ceci:
```js
var fs = require('fs')
fs.readFile('movie.mp4', function finishedReading(error, movieData) {
if (error) return console.error(error)
// do something with the movieData
})
```
## Evenements
Dans le cas où vous auriez besoin du module d'[evenements](http://nodejs.org/api/events.html), node vous propose 'event emitter', un module utilisé nativement par Node pour l'ensemble des ses API crée.
L'utilisation d'évènements est chose très commune en programmation, plus connu en tant que patron de conception ['Observation'](https://fr.wikipedia.org/wiki/Observateur_(patron_de_conception)) ou encore 'Observateur/Observable'. Tandis que les callbacks sont des relation one-to-one entre la chose qui attend le callback et celle qui appelle ce callback, les évènements répondent au même schema, a l'exception de leur système relationnel many-to-many.
La manière la plus simple d'imaginer les évènements est de considérer le fait qu'ils vous permettent de vous abonner à quelque chose. Vous pouvez dire : 'Quand X, fait Y', alors qu'un callback fonctionnera en 'Fait X puis Y'.
Ci-après une liste de cas d'utilisation où l'on privilégiera les évènements sur l'utilisation de callbacks:
- Canaux de discussion pour envoyer un message à un grand nombre d'observateurs
- Serveurs de jeux qui nécessitent de savoir quand de nouveaux joueurs se connectent, déconnectent, se déplacent, sautent ou tirent
- Moteur de jeu où vous voulez permettre aux développeurs de souscrire à des évènements comme `.on('jump', function() {})`
- Server web bas niveau où l'on veut exposer une API pour facilement accrocher des evenements comme `.on('incomingRequest')` or `.on('serverError')`
Si nous voulions écrire un module qui se connecte à un serveur de chat en utilisant uniquement des callbacks, cela ressemblerait à cela :
```js
var chatClient = require('my-chat-client')
function onConnect() {
// have the UI show we are connected
}
function onConnectionError(error) {
// show error to the user
}
function onDisconnect() {
// tell user that they have been disconnected
}
function onMessage(message) {
// show the chat room message in the UI
}
chatClient.connect(
'http://mychatserver.com',
onConnect,
onConnectionError,
onDisconnect,
onMessage
)
```
Comme vous pouvez le constater, cette méthode est particulièrement lourde, car il faut passer toutes les fonctions dans un ordre spécifique à la fonction `.connect`.
Avec une écriture évènementielle, nous obtiendriont ceci:
```js
var chatClient = require('my-chat-client').connect()
chatClient.on('connect', function() {
// have the UI show we are connected
})
chatClient.on('connectionError', function() {
// show error to the user
})
chatClient.on('disconnect', function() {
// tell user that they have been disconnected
})
chatClient.on('message', function() {
// show the chat room message in the UI
})
```
L'approche est similaire à la version en Callbacks, mais introduit les méthodes `.on`, qui rattachent des callbacks à un évènement. Ce qui signifie que vous pouvez choisir à quel évènement vous voulez souscrire depuis le `chatClient`. Vous pouvez aussi écouter le même évènement à de multiple reprises avec différents callbacks :
```js
var chatClient = require('my-chat-client').connect()
chatClient.on('message', logMessage)
chatClient.on('message', storeMessage)
function logMessage(message) {
console.log(message)
}
function storeMessage(message) {
myDatabase.save(message)
}
```
## Flux
Plus tôt dans le projet node, le file system et les APIs de réseaux avaient leurs schemas de fonctionnement séparés pour gérer les flux d'I/O. Par exemple, les fichiers du file system avaient des 'file descriptors', le module `fs` nécessitaient de la logique supplémentaire pour garder des traces de toutes ces choses, tandis que les modules de réseau ignoraient ces concepts. En dépit de différences sémantiques mineurs comme celles ci, au niveau fondamental, les deux groupes de code duplicaient beaucoup de fonctionnalités quand il s'agissait de lire les données en entrée et en sortir. Les équipes développant node on réalisé qu'il serait confus d'avoir à apprendre deux groupes sémantiques pour faire relativement la même chose, ils ont alors créée une nouvelle API nommé `Stream` à la fois pour le File system et pour le réseau.
Tout l'intéret de node réside dans sa capacité à faciliter l'interaction avec les file system et les réseaux, il était donc sensé d'avoir un seul schema de fonctionnement valable pour toutes les situations. La bonne nouvelle est que la plus part des cas d'utilisation (et il sont peu nombreux quoi qu'il en soit) on été couvert par node, et il est fort peu probable que node évolue de ce côté à l'avenir.
Il y a deux ressources formidables dont vous pouvez commencer à apprendre l'utilisation des flux node. La première est stream-adventure (cf. Apprentissage de Node Interactif), et la seconde s'appelle Stream Handbook.
### Stream Handbook
[stream-handbook](https://github.com/substack/stream-handbook#introduction) est un guide, similaire à celui ci, qui contient des références sur absolument tout ce que vous pouvez avoir besoin de savoir sur les flux.
[](https://github.com/substack/stream-handbook)
## Modules
Le Coeur de Node est composé d'une douzaine de modules. Certains bas niveau comme `events` ou `flux`, d'autres plus haut niveau comme `http` et `crypto`.
Ce design est intentionnel. Node core est supposé être léger, et les modules core doivent être réservés à fournir les outils nécessaires au traitement usuel des protocols I/O, de manière cross-platform.
Pour tout le reste, il a [npm](https://npmjs.org/). Tout le monde peut y créer de nouveaux modules qui ajoutront quelqueonque fonctionnalité et la publier sur npm. Au moment ou je vous écris ces lignes, il y a 34,000 modules sur npm.
### Comment trouver un module ?
Imaginez que vous souhaitez convertir un fichier PDF en TXT. Le meilleur moyen est de commencer par chercher `npm search pdf`:

Et il y a des tonnes de résultats! npm est relativement populaire, et vous trouverez généralement de multiples solutions potentielles pour vos besoins. Si vous filtrez suffisamment bien vos résultats vous devriez vous retrouver avec ceci :
- [hummus](https://github.com/galkahana/HummusJS/wiki/Features) - c++ pdf manipulator
- [mimeograph](https://github.com/steelThread/mimeograph) - api on a conglomeration of tools (poppler, tesseract, imagemagick etc)
- [pdftotextjs](https://npmjs.org/package/pdftotextjs) - wrapper around [pdftotext](https://en.wikipedia.org/wiki/Pdftotext)
- [pdf-text-extract](https://npmjs.org/package/pdf-text-extract) - another wrapper around pdftotext
- [pdf-extract](https://npmjs.org/package/pdf-extract) - wrapper around pdftotext, pdftk, tesseract, ghostscript
- [pdfutils](https://npmjs.org/package/pdfutils) - poppler wrapper
- [scissors](https://npmjs.org/package/scissors) - pdftk, ghostscript wrapper w/ high level api
- [textract](https://npmjs.org/package/textract) - pdftotext wrapper
- [pdfiijs](https://github.com/fagbokforlaget/pdfiijs) - pdf to inverted index using textiijs and poppler
- [pdf2json](https://github.com/modesty/pdf2json/blob/master/readme.md) - pure js pdf to json
Beaucoup de ces modules ont des fonctionnalités similaires, mais présentent des APIs alternatives. Ils requièrent aussi très souvent des dépendances externes comme (`apt-get install poppler`).
Voici une approche pour interpréter ces différents modules:
- `pdf2json` est le seul rédigé en pure JavaScript, ce qui signifie qu'il est aussi le plus simple à installer, notamment sur des petites configurations comme un raspberry pi ou un Windows ou le code natif n'est pas nécessairement cross platform.
- Les modules comme `mimeograph`, `hummus` et `pdf-extract` combinent chacuns de multiples modules bas niveau pour exposer une API haut niveau.
- Beaucoup de ces modules semblent reposer sur les outils de commande unix `pdftotext`/`poppler`.
Comparons les différences entre `pdftotextjs` et `pdf-text-extract`, tous deux étant fondées sur l'utilitaire `pdftotext`.

Tout deux possèdent :
- Des updates récentes
- Des liens vers vos repos Github (indispensable!)
- READMEs
- Une bonne popularité
- Sont sous license libre (tout le monde peut les utiliser librement)
En ne regardant que le `package.json` et les statistiques du module, il est difficile de se faire une bonne idée du meilleur choix possible. Comparons les READMEs:

Les deux possèdent des descriptions simples, des instructions d'installation, des badges CI, des exemples clairs pour lancer les tests. Fantastique! Mais lequel devons nous utiliser ? Comparons le code:

`pdftotextjs` contient environs 110 lignes de code, contre 40 pour `pdf-text-extract`, mais les deux peuvent essentiellement se réduire à cette ligne :
```
var child = shell.exec('pdftotext ' + self.options.additional.join(' '));
```
Est-ce que cela en fait un meilleur que l'autre ? Difficile à dire! Il est indispensable de *lire* le code pour vous faire vos propres conclusions. Si vous trouver un module qui vous plait, lancez `npm star modulename` pour donner votre feedback à npm sur un module qui vous a procuré une experience positive.
### Workflow de développement modulaire
npm diffère de la plupart des gestionnaires de packages par sa capacité à installer des modules des répertoires contenus à l'interieur de modules déja existants. Mêmes si vous n'y voyez pas encore d'intérêt, c'est là la clef du succes d'npm.
Beaucoup de gestionnaires de packages installent les choses de manière globale. Par exemple, si vous lancez `apt-get install couchdb` sur Debian Linux, il essayera d'installer la dernière version stable de CouchDB. Si vous essayez d'installer CouchDB en tant que dépendance d'un autre logiciel, et que ce logiciel nécessite une version anterieure de CouchDB, vous devrez désinstaller la version la plus récente de CouchDB puis installer la version historique. Vous ne pouvez donc pas avoir deux versions de CouchDB qui coexistent en parralèle car Debian ne sait installer les modules à qu'un endroit.
Et il n'y a pas que Debian qui fait cela. La plus part des gestionnaires de packages des langages de programmation fonctionnent ainsi. Pour solutionner ce problème, des environnements virtuels ont été développés comme [virtualenv](http://python-guide.readthedocs.org/en/latest/dev/virtualenvs/) pour Python ou [bundler](http://bundler.io/) pour Ruby. Ceux-ci découpent votre environnement en plusieurs environnements virtuels, un pour chaque projet. Toutefois, à l'interieur de chacun de ces environnnements, tout reste installé de manière globale. Les enviornnements virtuels n'adressent donc pas une réponse satisfaisante à notre problème et augmentent qui plus est le niveau de complexité de notre installation.
Avec npm, l'installation de modules globaux est contre-nature. De la même manière que vous ne devriez pas utilser de variables globales dans vos programmes JavaScript vous ne devriez pas installer de modules globaux (à moins que vous ayez besoin d'un module avec un executable binaire dans votre `PATH` globale, ce qui est loin d'être systématiquement le cas - nous en reparlerons).
#### Comment fonctionne `require`
Quand vous faites appel à `require('some_module')` voila ce qui se passe dans node:
1. Si un fichier qui s'appelle `some_module.js` existe dans le dossier courant, node le lancera. Autrement:
2. Node recherchera un dossier nommé `node_modules` dans le repertoire en cours, contenant un fichier `some_module` à l'interieur.
3. Si il ne trouve toujours pas, il montera d'un niveau et répètera l'opération 2.
Ce cycle se répètera jusqu'à ce que node atteignent le dossier root du filesystem. A ce moment, il continuera sa recherche dans les repertoires de modules globaux (comme `/usr/local/node_modules` sur Mac OS). Enfin, s'il ne trouve toujours rien, il enverra une erreur.
Pour illustrer ceci, voila un exemple:

Quand le dossier de travail en cour est `subsubfolder` et que `require('foo')` est appelé, node va chercher un dossier `subsubsubfolder/node_modules`. Dans le cas présent, sa recherche sera infructeuse, et le répertoire y est nommé par erreur `my_modules`. Node va donc remonter d'un répertoire et recommencer son opération, ce qui signifie qu'il cherchera alors `subfolder_B/node_modules` qui n'existera toujours pas. Enfin, la troisième tentative passera puisque `folder/node_modules` existe bel et bien *et* possède un répertoire nommé `foo` en son sein. Si `foo` n'y était pas, node aurait continué sa recherche jusqu'aux répertoire globaux.
Notez que s'il est appelé depuis `subfolder_B`, node ne trouvera jamais `subfolder_A/node_modules`, car il ne peut voir `folder/node_modules` que dans sa phase de remontée de l'arborescence.
Un des atouts de l'approche d'npm est que les modules peuvent installer leurs dépendances à des endroits spécifiques à leur version. Dans ce cas, le module `foo` est plutot populaire - il y en a trois copies, chacune à l'interieur de son dossier parent. Une explication pourrait être que chaque module parent requiert une version différente de `foo`, par exemple 'folder' qui requiert `foo@0.0.1`, `subfolder_A` de `foo@0.2.1` etc.
Maintenant, voila ce qui se produit si nous corrigeons notre problème de nom en remplaçant `my_modules` par son nom valide `node_modules`:

Pour tester quel module est véritablement chargé par node, vous pouvez utiliser `require.resolve('some_module')` qui vous montrera la path du module que node trouve dans sa remontée de l'arborescence. `require.resolve` est particulièrement utile pour double-checker que le module que vous *pensez* être chargé l'est *véritablement* -- parfois il y aura une autre version du même module qui sera plus proche de votre repertoire de travail actuel.
### Comment écrire un module
Maintenant que vous savez trouver un module et le `require`, vous pouvez écrire vos propres modules.
#### Le module le plus simple du monde
La légèreté des modules de Node est radicale. En voici l'un des plus simple possible :
`package.json`:
```js
{
"name": "number-one",
"version": "1.0.0"
}
```
`index.js`:
```js
module.exports = 1
```
Par défaut, node essaie de lancer `module/index.js` quand il lit `require('module')`. Aucun autre nom de fichier ne fonctionnera à moins que vous definissiez specifiez au champ `main` de `package.json` de pointer dessus.
Placez les deux fichiers dans un dossier nommé `number-one` (l'`id` dans package.json doit matcher un nom de dossier) et vous aurez un module node fonctionnel.
En appelant la fonction `require('number-one')` vous retournez la valeur qui est 'set' dans `module.exports`

Un moyen encore plus rapide de créer un module serait de lancer les commandes shell suivantes :
```sh
mkdir my_module
cd my_module
git init
git remote add git@github.com:yourusername/my_module.git
npm init
```
La commande `npm init` créera automatiquement un `package.json` valide pour vous. Si vous lancer un repo `git` existant, il définiera tout aussi automatiquement `package.json` à l'interieur.
#### Ajout de dépendances
Un module peut lister n'importe quel autre module depuis npm our GitHub dans le champ `dépendances` de `package.json`. Pour installer un module `request` en tant que nouvelle dépendance et l'ajouter automatiquement au `package.json`, vous pouvez lancer ceci depuis votre répertoire root :
```sh
npm install --save request
```
Cela installera une copie de `request` dans le `node_modules` le plus proche et notre `package.json` ressemblera ainsi à cela:
```
{
"id": "number-one",
"version": "1.0.0",
"dependencies": {
"request": "~2.22.0"
}
}
```
Par défaut `npm install` récupèrera la dernière version publiée du module.
## Developpez cote client avec npm
npm est victime d'un vice de pensé assez fréquent. `Node` faisant parti de son nom, il est courant de penser qu'il ne gère que des modules JS côté serveur, ce qui est absolument faux! npm signifie Node Packaged Module, c'est-à-dire des module que Node package pour vous. Ces modules peuvent être n'importe quoi - Ce ne sont que des repertoires ou des fichiers encapsulés dans des .tar.gz et un fichié nommé `package.json` qui explicite la version du module ainsi que la liste de toutes ses dépendances (ainsi que leur propre version de module pour que seules les versions connues pour fonctionner avec notre module ne soient installées automatiquement). Les dépendances ne sont que des modules, qui peuvent eux mêmes avoir des dépendances, et ainsi de suite.
[browserify](http://browserify.org/) est un utilitaire écrit en node qui tente de traduire n'importe quel module node en code lisible par un browser. Bien que *beaucoup de modules soient compatibles*, tous ne le sont pas (Les browsers ne peuvent par exemple pas heberger un serveur HTTP).
Pour essayer npm en browser, vous pouvez utiliser [RequireBin](http://requirebin.com/), qui est une application que j'ai réalisé qui tire profit de [Browserify-CDN](https://github.com/jesusabdullah/browserify-cdn). Elle utilise browserify en interne et renvoi l'output à travers HTTP (en lieu et place de la ligne de commande communément utilisé par browserify.)
Essayez maintenant de mettre ce code dans RequireBin et lancez le boutton de preview:
```js
var reverse = require('ascii-art-reverse')
// makes a visible HTML console
require('console-log').show(true)
var coolbear =
" ('-^-/') \n" +
" `o__o' ] \n" +
" (_Y_) _/ \n" +
" _..`--'-.`, \n" +
" (__)_,--(__) \n" +
" 7: ; 1 \n" +
" _/,`-.-' : \n" +
" (_,)-~~(_,) \n"
setInterval(function() { console.log(coolbear) }, 1000)
setTimeout(function() {
setInterval(function() { console.log(reverse(coolbear)) }, 1000)
}, 500)
```
Ou testez [un exemple plus complexe](http://requirebin.com/?gist=6031068) (Vous êtes libre de changer le code pour voir ce qu'il se produit):
[](http://requirebin.com/embed?gist=6031068)
## Suivez le mouvement
Comme tous les bons outils, node est particulièrement adapté à certains cas d'utilisation. Par exemple: Rails, le framework web populaire, est fantastique pour modeliser de la [logique métier complexe](http://en.wikipedia.org/wiki/Business_logic), c'est-à-dire utiliser le code pour représenter des objets métiers comme des comptes clients, des prêts, des itinéraires, ou encore des stocks. Tandis qu'il est techniquement possible de faire la même chose avec Node, nous rencontrerions quelques désagréments car Node n'a pas été conçu pour résoudre ce type de problématiques. Retenez que chaque outil se concentre sur des problèmes différents! Fort heureusement, ce guide vous aidera à comprendre les forces de node afin que vous sachiez intuitivement à quel moment y avoir recours.
### Quelles sont les limites du scope de node ?
Node n'est fondamentalement conçu que pour gérer les I/O à travers le file system et les réseaux, et laisse les fonctionnalités plus fantaisistes aux modules tiers. Voici quelques exemples de choses qui dépassent le perimètre d'action de node:
#### Frameworks Web
Il existe des frameworks web basés sur node (framework signifiant un agglomérat de solutions qui cherchent à solutionner des problèmes au niveau comme de la logique métier), mais node n'est pas un framework à lui seul. Les frameworks web conçu par dessus node ne prennent pas les mêmes décisions concernant l'ajout de complexité, d'abstraction ou de compromis que node, et ont souvent d'autres priorités que les simples problématiques d'I/O.
#### Syntaxe du langage
Node utilise JavaScript et adopte donc sa syntaxe. Felix Geisendörfer présente une synthèse plutôt bonne du 'style node' [here](https://github.com/felixge/node-style-guide).
#### Niveau d'abstraction du langage
Quand cela est possible, node utilisera le moyen le plus simple possible d'accomplir quelque chose. Plus fantaisiste sera votre JavaScript plus vous apportez de complexité. Programmer est difficile, particulièrement en JavaScript où vous avez 1000 manières différentes de solutionner un même problème ! C'est pourquoi node essaye toujours d'utiliser la solution la plus simple universelle. Si vous tentez de résoudre un problème qui appelle une solution complexe, et que vous n'êtes pas satisfait des solutions en pure JS que node implémente, vous êtes libre de les résoudre à l'interieur de votre module en utilisant le niveau d'abstraction que vous souhaitez.
Un exemple parfait pour cela est l'utilisation que node fait des callbacks. Plus tôt, node a fait l'experience d'une feature nommé 'promesses' qui ajoutaient un certain nombre de features pour rendre le code asynchrone plus linéaire. Les promesses furent retirées du coeur node pour plusieurs raisons :
- Elles sont plus complexes que les callbacks
- Elles peuvent être implémentées avec userland (distribué en module tiers via npm)
Considérez une des choses les plus universelles et basique proposée par node: lire un fichier. Quand vous lisez un fichier vous voulez être au courant de l'apparition d'une erreur, comme lorsque votre disque dur meurt au milieu d'une lecture. Si node possédait des promesses, tout le monde devrait produire un code comme ceci :
```js
fs.readFile('movie.mp4')
.then(function(data) {
// do stuff with data
})
.error(function(error) {
// handle error
})
```
Cela ajouterait de la complexité, et tout le monde ne souhaite pas cela. A la place de deux fonctions différentes, node n'appelle qu'une fonction de callback. Les règles sont les suivantes :
- Quand il n'y a pas d'erreur, passez null en premier argument.
- Quand il y a une erreur, passez la en premier argument.
- Le reste des arguments peut être utilisé pour ce que vous désirez (en général les données ou réponses de vos flux d'I/O, puisque vous utiliserez généralement node à cet fin).
En conséquence, voila le style node en callback:
```js
fs.readFile('movie.mp4', function(err, data) {
// handle error, do stuff with data
})
```
#### Threads/fibers/non-event-based concurrency solutions
Note : Si vous ne savez pas ce que ces choses signifient, il sera probablement plus simple d'apprendre node, puisque désapprendre constitue tout autant de travail qu'apprendre.
Node utilise des threads internes pour accelérer les choses, mais ne les expose par à l'utilisateur. Si vous êtes un utilisateur technique et que vous demandez pourquoi node est conçu ainsi, alors vous devriez absolument lire [the design of libuv](http://nikhilm.github.com/uvbook/), la couche I/O en C++ sur laquelle node est fondé.
## License

Creative Commons Attribution License (do whatever, just attribute me)
http://creativecommons.org/licenses/by/2.0/
L'icone de dont provient de [Noun Project](http://thenounproject.com/term/donate/285/)
================================================
FILE: readme.md
================================================
# The Art of Node
## An introduction to Node.js
This document is intended for readers who know at least a little bit of a couple of things:
- a scripting language like JavaScript, Ruby, Python, Perl, etc. If you aren't a programmer yet then it is probably easier to start by reading [JavaScript for Cats](http://jsforcats.com/). :cat2:
- git and github. These are the open source collaboration tools that people in the node community use to share modules. You just need to know the basics. Here are three great intro tutorials: [1](https://github.com/jlord/git-it-electron#readme), [2](http://ericsteinborn.com/github-for-cats/#/), [3](http://opensourcerer.diy.org/)
## Table of contents
- [Learn node interactively](#learn-node-interactively)
- [Understanding node](#understanding-node)
- [Core modules](#core-modules)
- [Callbacks](#callbacks)
- [Events](#events)
- [Streams](#streams)
- [Modules and npm](#modules)
- [Client side development with npm](#client-side-development-with-npm)
- [Going with the grain](#going-with-the-grain)
## Learn node interactively
In addition to reading this guide it's super important to also bust out your favorite text editor and actually write some node code. I always find that when I just read some code in a book it never really clicks, but learning by writing code is a good way to grasp new programming concepts.
### NodeSchool.io
[NodeSchool.io](http://nodeschool.io/) is a series of free + open source interactive workshops that teach you the principles of Node.js and beyond.
[Learn You The Node.js](https://github.com/workshopper/learnyounode#learn-you-the-nodejs-for-much-win) is the introductory NodeSchool.io workshop. It's a set of programming problems that introduce you to common node patterns. It comes packaged as a command line program.
[](https://github.com/rvagg/learnyounode#learn-you-the-nodejs-for-much-win)
You can install it with npm:
```
# install
npm install learnyounode -g
# start the menu
learnyounode
```
## Understanding node
Node.js is an open source project designed to help you write JavaScript programs that talk to networks, file systems or other I/O (input/output, reading/writing) sources. That's it! It is just a simple and stable I/O platform that you are encouraged to build modules on top of.
What are some examples of I/O? Here is a diagram of an application that I made with node that shows many I/O sources:

If you don't understand all of the different things in the diagram it is completely okay. The point is to show that a single node process (the hexagon in the middle) can act as the broker between all of the different I/O endpoints (orange and purple represent I/O).
Usually building these kinds of systems is either:
- difficult to code but yields super fast results (like writing your web servers from scratch in C)
- easy to code but not very speedy/robust (like when someone tries to upload a 5GB file and your server crashes)
Node's goal is to strike a balance between these two: relatively easy to understand and use and fast enough for most use cases.
Node isn't either of the following:
- A web framework (like Rails or Django, though it can be used to make such things)
- A programming language (it uses JavaScript but node isn't its own language)
Instead, node is somewhere in the middle. It is:
- Designed to be simple and therefore relatively easy to understand and use
- Useful for I/O based programs that need to be fast and/or handle lots of connections
At a lower level, node can be described as a tool for writing two major types of programs:
- Network programs using the protocols of the web: HTTP, TCP, UDP, DNS and SSL
- Programs that read and write data to the filesystem or local processes/memory
What is an "I/O based program"? Here are some common I/O sources:
- Databases (e.g. MySQL, PostgreSQL, MongoDB, Redis, CouchDB)
- APIs (e.g. Twitter, Facebook, Apple Push Notifications)
- HTTP/WebSocket connections (from users of a web app)
- Files (image resizer, video editor, internet radio)
Node does I/O in a way that is [asynchronous](https://en.wikipedia.org/wiki/Asynchronous_I/O) which lets it handle lots of different things simultaneously. For example, if you go down to a fast food joint and order a cheeseburger they will immediately take your order and then make you wait around until the cheeseburger is ready. In the meantime they can take other orders and start cooking cheeseburgers for other people. Imagine if you had to wait at the register for your cheeseburger, blocking all other people in line from ordering while they cooked your burger! This is called **blocking I/O** because all I/O (cooking cheeseburgers) happens one at a time. Node, on the other hand, is **non-blocking**, which means it can cook many cheeseburgers at once.
Here are some fun things made easy with node thanks to its non-blocking nature:
- Control [flying quadcopters](http://www.nodecopter.com/)
- Write IRC chat bots
- Create [walking biped robots](https://www.youtube.com/watch?v=jf-cEB3U2UQ)
## Core modules
Firstly I would recommend that you get node installed on your computer. The easiest way is to visit [nodejs.org](http://nodejs.org) and click `Install`.
Node has a small core group of modules (commonly referred to as 'node core') that are presented as the public API that you are intended to write programs with. For working with file systems there is the `fs` module and for networks there are modules like `net` (TCP), `http`, `dgram` (UDP).
In addition to `fs` and network modules there are a number of other base modules in node core. There is a module for asynchronously resolving DNS queries called `dns`, a module for getting OS specific information like the tmpdir location called `os`, a module for allocating binary chunks of memory called `buffer`, some modules for parsing urls and paths (`url`, `querystring`, `path`), etc. Most if not all of the modules in node core are there to support node's main use case: writing fast programs that talk to file systems or networks.
Node handles I/O with: callbacks, events, streams and modules. If you learn how these four things work then you will be able to go into any module in node core and have a basic understanding about how to interface with it.
## Callbacks
This is the most important topic to understand if you want to understand how to use node. Nearly everything in node uses callbacks. They weren't invented by node, they are just part of the JavaScript language.
Callbacks are functions that are executed asynchronously, or at a later time. Instead of the code reading top to bottom procedurally, async programs may execute different functions at different times based on the order and speed that earlier functions like http requests or file system reads happen.
The difference can be confusing since determining if a function is asynchronous or not depends a lot on context. Here is a simple synchronous example, meaning you can read the code top to bottom just like a book:
```js
var myNumber = 1
function addOne() { myNumber++ } // define the function
addOne() // run the function
console.log(myNumber) // logs out 2
```
The code here defines a function and then on the next line calls that function, without waiting for anything. When the function is called it immediately adds 1 to the number, so we can expect that after we call the function the number should be 2. This is the expectation of synchronous code - it sequentially runs top to bottom.
Node, however, uses mostly asynchronous code. Let's use node to read our number from a file called `number.txt`:
```js
var fs = require('fs') // require is a special function provided by node
var myNumber = undefined // we don't know what the number is yet since it is stored in a file
function addOne() {
fs.readFile('number.txt', function doneReading(err, fileContents) {
myNumber = parseInt(fileContents)
myNumber++
})
}
addOne()
console.log(myNumber) // logs out undefined -- this line gets run before readFile is done
```
Why do we get `undefined` when we log out the number this time? In this code we use the `fs.readFile` method, which happens to be an asynchronous method. Usually things that have to talk to hard drives or networks will be asynchronous. If they just have to access things in memory or do some work on the CPU they will be synchronous. The reason for this is that I/O is reallyyy reallyyy sloowwww. A ballpark figure would be that talking to a hard drive is about 100,000 times slower than talking to memory (e.g. RAM).
When we run this program all of the functions are immediately defined, but they don't all execute immediately. This is a fundamental thing to understand about async programming. When `addOne` is called it kicks off a `readFile` and then moves on to the next thing that is ready to execute. If there is nothing to execute node will either wait for pending fs/network operations to finish or it will stop running and exit to the command line.
When `readFile` is done reading the file (this may take anywhere from milliseconds to seconds to minutes depending on how fast the hard drive is) it will run the `doneReading` function and give it an error (if there was an error) and the file contents.
The reason we got `undefined` above is that nowhere in our code exists logic that tells the `console.log` statement to wait until the `readFile` statement finishes before it prints out the number.
If you have some code that you want to be able to execute over and over again, or at a later time, the first step is to put that code inside a function. Then you can call the function whenever you want to run your code. It helps to give your functions descriptive names.
Callbacks are just functions that get executed at some later time. The key to understanding callbacks is to realize that they are used when you don't know **when** some async operation will complete, but you do know **where** the operation will complete — the last line of the async function! The top-to-bottom order that you declare callbacks does not necessarily matter, only the logical/hierarchical nesting of them. First you split your code up into functions, and then use callbacks to declare if one function depends on another function finishing.
The `fs.readFile` method is provided by node, is asynchronous, and happens to take a long time to finish. Consider what it does: it has to go to the operating system, which in turn has to go to the file system, which lives on a hard drive that may or may not be spinning at thousands of revolutions per minute. Then it has to use a magnetic head to read data and send it back up through the layers back into your javascript program. You give `readFile` a function (known as a callback) that it will call after it has retrieved the data from the file system. It puts the data it retrieved into a javascript variable and calls your function (callback) with that variable. In this case the variable is called `fileContents` because it contains the contents of the file that was read.
Think of the restaurant example at the beginning of this tutorial. At many restaurants you get a number to put on your table while you wait for your food. These are a lot like callbacks. They tell the server what to do after your cheeseburger is done.
Let's put our `console.log` statement into a function and pass it in as a callback:
```js
var fs = require('fs')
var myNumber = undefined
function addOne(callback) {
fs.readFile('number.txt', function doneReading(err, fileContents) {
myNumber = parseInt(fileContents)
myNumber++
callback()
})
}
function logMyNumber() {
console.log(myNumber)
}
addOne(logMyNumber)
```
Now the `logMyNumber` function can get passed in as an argument that will become the `callback` variable inside the `addOne` function. After `readFile` is done the `callback` variable will be invoked (`callback()`). Only functions can be invoked, so if you pass in anything other than a function it will cause an error.
When a function gets invoked in javascript the code inside that function will immediately get executed. In this case our log statement will execute since `callback` is actually `logMyNumber`. Remember, just because you *define* a function it doesn't mean it will execute. You have to *invoke* a function for that to happen.
To break down this example even more, here is a timeline of events that happen when we run this program:
- 1: The code is parsed, which means if there are any syntax errors they would make the program break. During this initial phase, `fs` and `myNumber` are declared as variables while `addOne` and `logMyNumber` are declared as functions. Note that these are just declarations. Neither function has been called nor invoked yet.
- 2: When the last line of our program gets executed `addOne` is invoked with the `logMyNumber` function passed as its `callback` argument. Invoking `addOne` will first run the asynchronous `fs.readFile` function. This part of the program takes a while to finish.
- 3: With nothing to do, node idles for a bit as it waits for `readFile` to finish. If there was anything else to do during this time, node would be available for work.
- 4: As soon as `readFile` finishes it executes its callback, `doneReading`, which parses `fileContents` for an integer called `myNumber`, increments `myNumber` and then immediately invokes the function that `addOne` passed in (its callback), `logMyNumber`.
Perhaps the most confusing part of programming with callbacks is how functions are just objects that can be stored in variables and passed around with different names. Giving simple and descriptive names to your variables is important in making your code readable by others. Generally speaking in node programs when you see a variable like `callback` or `cb` you can assume it is a function.
You may have heard the terms 'evented programming' or 'event loop'. They refer to the way that `readFile` is implemented. Node first dispatches the `readFile` operation and then waits for `readFile` to send it an event that it has completed. While it is waiting node can go check on other things. Inside node there is a list of things that are dispatched but haven't reported back yet, so node loops over the list again and again checking to see if they are finished. After they finished they get 'processed', e.g. any callbacks that depended on them finishing will get invoked.
Here is a pseudocode version of the above example:
```js
function addOne(thenRunThisFunction) {
waitAMinuteAsync(function waitedAMinute() {
thenRunThisFunction()
})
}
addOne(function thisGetsRunAfterAddOneFinishes() {})
```
Imagine you had 3 async functions `a`, `b` and `c`. Each one takes 1 minute to run and after it finishes it calls a callback (that gets passed in the first argument). If you wanted to tell node 'start running a, then run b after a finishes, and then run c after b finishes' it would look like this:
```js
a(function() {
b(function() {
c()
})
})
```
When this code gets executed, `a` will immediately start running, then a minute later it will finish and call `b`, then a minute later it will finish and call `c` and finally 3 minutes later node will stop running since there would be nothing more to do. There are definitely more elegant ways to write the above example, but the point is that if you have code that has to wait for some other async code to finish then you express that dependency by putting your code in functions that get passed around as callbacks.
The design of node requires you to think non-linearly. Consider this list of operations:
```
read a file
process that file
```
If you were to turn this into pseudocode you would end up with this:
```
var file = readFile()
processFile(file)
```
This kind of linear (step-by-step, in order) code isn't the way that node works. If this code were to get executed then `readFile` and `processFile` would both get executed at the same exact time. This doesn't make sense since `readFile` will take a while to complete. Instead you need to express that `processFile` depends on `readFile` finishing. This is exactly what callbacks are for! And because of the way that JavaScript works you can write this dependency many different ways:
```js
var fs = require('fs')
fs.readFile('movie.mp4', finishedReading)
function finishedReading(error, movieData) {
if (error) return console.error(error)
// do something with the movieData
}
```
But you could also structure your code like this and it would still work:
```js
var fs = require('fs')
function finishedReading(error, movieData) {
if (error) return console.error(error)
// do something with the movieData
}
fs.readFile('movie.mp4', finishedReading)
```
Or even like this:
```js
var fs = require('fs')
fs.readFile('movie.mp4', function finishedReading(error, movieData) {
if (error) return console.error(error)
// do something with the movieData
})
```
## Events
In node if you require the [events](https://nodejs.org/api/events.html) module you can use the so-called 'event emitter' that node itself uses for all of its APIs that emit things.
Events are a common pattern in programming, known more widely as the ['observer pattern'](https://en.wikipedia.org/wiki/Observer_pattern) or 'pub/sub' (publish/subscribe). Whereas callbacks are a one-to-one relationship between the thing waiting for the callback and the thing calling the callback, events are the same exact pattern except with a many-to-many API.
The easiest way to think about events is that they let you subscribe to things. You can say 'when X do Y', whereas with plain callbacks it is 'do X then Y'.
Here are few common use cases for using events instead of plain callbacks:
- Chat room where you want to broadcast messages to many listeners
- Game server that needs to know when new players connect, disconnect, move, shoot and jump
- Game engine where you want to let game developers subscribe to events like `.on('jump', function() {})`
- A low level web server that wants to expose an API to easily hook into events that happen like `.on('incomingRequest')` or `.on('serverError')`
If we were trying to write a module that connects to a chat server using only callbacks it would look like this:
```js
var chatClient = require('my-chat-client')
function onConnect() {
// have the UI show we are connected
}
function onConnectionError(error) {
// show error to the user
}
function onDisconnect() {
// tell user that they have been disconnected
}
function onMessage(message) {
// show the chat room message in the UI
}
chatClient.connect(
'http://mychatserver.com',
onConnect,
onConnectionError,
onDisconnect,
onMessage
)
```
As you can see this is really cumbersome because of all of the functions that you have to pass in a specific order to the `.connect` function. Writing this with events would look like this:
```js
var chatClient = require('my-chat-client').connect()
chatClient.on('connect', function() {
// have the UI show we are connected
})
chatClient.on('connectionError', function() {
// show error to the user
})
chatClient.on('disconnect', function() {
// tell user that they have been disconnected
})
chatClient.on('message', function() {
// show the chat room message in the UI
})
```
This approach is similar to the pure-callback approach but introduces the `.on` method, which subscribes a callback to an event. This means you can choose which events you want to subscribe to from the `chatClient`. You can also subscribe to the same event multiple times with different callbacks:
```js
var chatClient = require('my-chat-client').connect()
chatClient.on('message', logMessage)
chatClient.on('message', storeMessage)
function logMessage(message) {
console.log(message)
}
function storeMessage(message) {
myDatabase.save(message)
}
```
## Streams
Early on in the node project the file system and network APIs had their own separate patterns for dealing with streaming I/O. For example, files in a file system have things called 'file descriptors' so the `fs` module had to have extra logic to keep track of these things whereas the network modules didn't have such a concept. Despite minor differences in semantics like these, at a fundamental level both groups of code were duplicating a lot of functionality when it came to reading data in and out. The team working on node realized that it would be confusing to have to learn two sets of semantics to essentially do the same thing so they made a new API called the `Stream` and made all the network and file system code use it.
The whole point of node is to make it easy to deal with file systems and networks so it made sense to have one pattern that was used everywhere. The good news is that most of the patterns like these (there are only a few anyway) have been figured out at this point and it is very unlikely that node will change that much in the future.
There are already two great resources that you can use to learn about node streams. One is the stream-adventure (see the Learn Node Interactively section) and the other is a reference called the Stream Handbook.
### Stream Handbook
[stream-handbook](https://github.com/substack/stream-handbook#introduction) is a guide, similar to this one, that contains a reference for everything you could possibly need to know about streams.
[](https://github.com/substack/stream-handbook)
## Modules
Node core is made up of about two dozen modules, some lower level ones like `events` and `stream` some higher level ones like `http` and `crypto`.
This design is intentional. Node core is supposed to be small, and the modules in core should be focused on providing tools for working with common I/O protocols and formats in a way that is cross-platform.
For everything else there is [npm](https://www.npmjs.com/). Anyone can create a new node module that adds some functionality and publish it to npm. As of the time of this writing there are 34,000 modules on npm.
### How to find a module
Imagine you are trying to convert PDF files into TXT files. The best place to start is by doing `npm search pdf`:

There are a ton of results! npm is quite popular and you will usually be able to find multiple potential solutions. If you go through each module and whittle down the results into a more narrow set (filtering out things like PDF generation modules) you'll end up with these:
- [hummus](https://github.com/galkahana/HummusJS/wiki/Features) - c++ pdf manipulator
- [mimeograph](https://github.com/steelThread/mimeograph) - api on a conglomeration of tools (poppler, tesseract, imagemagick etc)
- [pdftotextjs](https://www.npmjs.com/package/pdftotextjs) - wrapper around [pdftotext](https://en.wikipedia.org/wiki/Pdftotext)
- [pdf-text-extract](https://www.npmjs.com/package/pdf-text-extract) - another wrapper around pdftotext
- [pdf-extract](https://www.npmjs.com/package/pdf-extract) - wrapper around pdftotext, pdftk, tesseract, ghostscript
- [pdfutils](https://www.npmjs.com/package/pdfutils) - poppler wrapper
- [scissors](https://www.npmjs.com/package/scissors) - pdftk, ghostscript wrapper w/ high level api
- [textract](https://www.npmjs.com/package/textract) - pdftotext wrapper
- [pdfiijs](https://github.com/fagbokforlaget/pdfiijs) - pdf to inverted index using textiijs and poppler
- [pdf2json](https://github.com/modesty/pdf2json/blob/master/readme.md) - pure js pdf to json
A lot of the modules have overlapping functionality but present alternate APIs and most of them require external dependencies (like `apt-get install poppler`).
Here are some different ways to interpret the modules:
- `pdf2json` is the only one that is written in pure JavaScript, which means it is the easiest to install, especially on low power devices like the raspberry pi or on Windows where native code might not be cross platform.
- modules like `mimeograph`, `hummus` and `pdf-extract` each combine multiple lower level modules to expose a high level API
- a lot of modules seem to sit on top of the `pdftotext`/`poppler` unix command line tools
Lets compare the differences between `pdftotextjs` and `pdf-text-extract`, both of which are are wrappers around the `pdftotext` utility.

Both of these:
- were updated relatively recently
- have github repositories linked (this is very important!)
- have READMEs
- have at least some number of people installing them every week
- are liberally licensed (anyone can use them)
Just looking at the `package.json` + module statistics it's hard to get a feeling about which one might be the right choice. Let's compare the READMEs:

Both have simple descriptions, CI badges, installation instructions, clear examples and instructions for running the tests. Great! But which one do we use? Let's compare the code:

`pdftotextjs` is around 110 lines of code, and `pdf-text-extract` is around 40, but both essentially boil down to this line:
```
var child = shell.exec('pdftotext ' + self.options.additional.join(' '));
```
Does this make one any better than the other? Hard to say! It's important to actually *read* the code and make your own conclusions. If you find a module you like, use `npm star modulename` to give npm feedback about modules that you had a positive experience with.
### Modular development workflow
npm is different from most package managers in that it installs modules into a folder inside of other existing modules. The previous sentence might not make sense right now but it is the key to npm's success.
Many package managers install things globally. For instance, if you `apt-get install couchdb` on Debian Linux it will try to install the latest stable version of CouchDB. If you are trying to install CouchDB as a dependency of some other piece of software and that software needs an older version of CouchDB, you have to uninstall the newer version of CouchDB and then install the older version. You can't have two versions of CouchDB installed because Debian only knows how to install things into one place.
It's not just Debian that does this. Most programming language package managers work this way too. To address the global dependencies problem described above there have been virtual environment developed like [virtualenv](http://python-guide.readthedocs.org/en/latest/dev/virtualenvs/) for Python or [bundler](http://bundler.io/) for Ruby. These just split your environment up in to many virtual environments, one for each project, but inside each environment dependencies are still globally installed. Virtual environments don't always solve the problem, sometimes they just multiply it by adding additional layers of complexity.
With npm installing global modules is an anti-pattern. Just like how you shouldn't use global variables in your JavaScript programs you also shouldn't install global modules (unless you need a module with an executable binary to show up in your global `PATH`, but you don't always need to do this -- more on this later).
#### How `require` works
When you call `require('some_module')` in node here is what happens:
1. if a file called `some_module.js` exists in the current folder node will load that, otherwise:
2. node looks in the current folder for a `node_modules` folder with a `some_module` folder in it
3. if it doesn't find it, it will go up one folder and repeat step 2
This cycle repeats until node reaches the root folder of the filesystem, at which point it will then check any global module folders (e.g. `/usr/local/node_modules` on Mac OS) and if it still doesn't find `some_module` it will throw an exception.
Here's a visual example:

When the current working directory is `subsubfolder` and `require('foo')` is called, node will look for the folder called `subsubfolder/node_modules`. In this case it won't find it -- the folder there is mistakenly called `my_modules`. Then node will go up one folder and try again, meaning it then looks for `subfolder_B/node_modules`, which also doesn't exist. Third try is a charm, though, as `folder/node_modules` does exist *and* has a folder called `foo` inside of it. If `foo` wasn't in there node would continue its search up the directory tree.
Note that if called from `subfolder_B` node will never find `subfolder_A/node_modules`, it can only see `folder/node_modules` on its way up the tree.
One of the benefits of npm's approach is that modules can install their dependent modules at specific known working versions. In this case the module `foo` is quite popular - there are three copies of it, each one inside its parent module folder. The reasoning for this could be that each parent module needed a different version of `foo`, e.g. 'folder' needs `foo@0.0.1`, `subfolder_A` needs `foo@0.2.1` etc.
Here's what happens when we fix the folder naming error by changing `my_modules` to the correct name `node_modules`:

To test out which module actually gets loaded by node, you can use the `require.resolve('some_module')` command, which will show you the path to the module that node finds as a result of the tree climbing process. `require.resolve` can be useful when double-checking that the module that you *think* is getting loaded is *actually* getting loaded -- sometimes there is another version of the same module closer to your current working directory than the one you intend to load.
### How to write a module
Now that you know how to find modules and require them you can start writing your own modules.
#### The simplest possible module
Node modules are radically lightweight. Here is one of the simplest possible node modules:
`package.json`:
```js
{
"name": "number-one",
"version": "1.0.0"
}
```
`index.js`:
```js
module.exports = 1
```
By default node tries to load `module/index.js` when you `require('module')`, any other file name won't work unless you set the `main` field of `package.json` to point to it.
Put both of those files in a folder called `number-one` (the `name` in `package.json` must match the folder name) and you'll have a working node module.
Calling the function `require('number-one')` returns the value of whatever `module.exports` is set to inside the module:

An even quicker way to create a module is to run these commands:
```sh
mkdir my_module
cd my_module
git init
git remote add git@github.com:yourusername/my_module.git
npm init
```
Running `npm init` will create a valid `package.json` for you and if you run it in an existing `git` repo it will set the `repositories` field inside `package.json` automatically as well!
#### Adding dependencies
A module can list any other modules from npm or GitHub in the `dependencies` field of `package.json`. To install the `request` module as a new dependency and automatically add it to `package.json` run this from your module root directory:
```sh
npm install --save request
```
This installs a copy of `request` into the closest `node_modules` folder and makes our `package.json` look something like this:
```
{
"id": "number-one",
"version": "1.0.0",
"dependencies": {
"request": "~2.22.0"
}
}
```
By default `npm install` will grab the latest published version of a module.
## Client side development with npm
A common misconception about npm is that since it has 'Node' in the name that it must only be used for server side JS modules. This is completely untrue! npm actually stands for Node Packaged Modules, e.g. modules that Node packages together for you. The modules themselves can be whatever you want -- they are just a folder of files wrapped up in a .tar.gz, and a file called `package.json` that declares the module version and a list of all modules that are dependencies of the module (as well as their version numbers so the working versions get installed automatically). It's turtles all the way down - module dependencies are just modules, and those modules can have dependencies etc. etc. etc.
[browserify](http://browserify.org/) is a utility written in Node that tries to convert any node module into code that can be run in browsers. Not all modules work (browsers can't do things like host an HTTP server), but a lot of modules on NPM *will* work.
To try out npm in the browser you can use [RequireBin](http://requirebin.com/), an app I made that takes advantage of [Browserify-CDN](https://github.com/jfhbrook/wzrd.in), which internally uses browserify but returns the output through HTTP (instead of the command line -- which is how browserify is usually used).
Try putting this code into RequireBin and then hit the preview button:
```js
var reverse = require('ascii-art-reverse')
// makes a visible HTML console
require('console-log').show(true)
var coolbear =
" ('-^-/') \n" +
" `o__o' ] \n" +
" (_Y_) _/ \n" +
" _..`--'-.`, \n" +
" (__)_,--(__) \n" +
" 7: ; 1 \n" +
" _/,`-.-' : \n" +
" (_,)-~~(_,) \n"
setInterval(function() { console.log(coolbear) }, 1000)
setTimeout(function() {
setInterval(function() { console.log(reverse(coolbear)) }, 1000)
}, 500)
```
Or check out a [more complicated example](http://requirebin.com/?gist=679b58d4237eaca37173) (feel free to change the code and see what happens):
[](http://requirebin.com/embed?gist=679b58d4237eaca37173)
## Going with the grain
Like any good tool, node is best suited for a certain set of use cases. For example: Rails, the popular web framework, is great for modeling complex [business logic](https://en.wikipedia.org/wiki/Business_logic), e.g. using code to represent real life business objects like accounts, loan, itineraries, and inventories. While it is technically possible to do the same type of thing using node, there would be definite drawbacks since node is designed for solving I/O problems and it doesn't know much about 'business logic'. Each tool focuses on different problems. Hopefully this guide will help you gain an intuitive understanding of the strengths of node so that you know when it can be useful to you.
### What is outside of node's scope?
Fundamentally node is just a tool used for managing I/O across file systems and networks, and it leaves other more fancy functionality up to third party modules. Here are some things that are outside the scope of node:
#### Web frameworks
There are a number of web frameworks built on top of node (framework meaning a bundle of solutions that attempts to address some high level problem like modeling business logic), but node is not a web framework. Web frameworks that are written using node don't always make the same kind of decisions about adding complexity, abstractions and tradeoffs that node does and may have other priorities.
#### Language syntax
Node uses JavaScript and doesn't change anything about it. Felix Geisendörfer has a pretty good write-up of the 'node style' [here](https://github.com/felixge/node-style-guide).
#### Language abstraction
When possible node will use the simplest possible way of accomplishing something. The 'fancier' you make your JavaScript the more complexity and tradeoffs you introduce. Programming is hard, especially in JS where there are 1000 solutions to every problem! It is for this reason that node tries to always pick the simplest, most universal option. If you are solving a problem that calls for a complex solution and you are unsatisfied with the 'vanilla JS solutions' that node implements, you are free to solve it inside your app or module using whichever abstractions you prefer.
A great example of this is node's use of callbacks. Early on node experimented with a feature called 'promises' that added a number of features to make async code appear more linear. It was taken out of node core for a few reasons:
- they are more complex than callbacks
- they can be implemented in userland (distributed on npm as third party modules)
Consider one of the most universal and basic things that node does: reading a file. When you read a file you want to know when errors happen, like when your hard drive dies in the middle of your read. If node had promises everyone would have to branch their code like this:
```js
fs.readFile('movie.mp4')
.then(function(data) {
// do stuff with data
})
.error(function(error) {
// handle error
})
```
This adds complexity, and not everyone wants that. Instead of two separate functions node just uses a single callback function. Here are the rules:
- When there is no error pass null as the first argument
- When there is an error, pass it as the first argument
- The rest of the arguments can be used for anything (usually data or responses since most stuff in node is reading or writing things)
Hence, the node callback style:
```js
fs.readFile('movie.mp4', function(err, data) {
// handle error, do stuff with data
})
```
#### Threads/fibers/non-event-based concurrency solutions
Note: If you don't know what these things mean then you will likely have an easier time learning node, since unlearning things is just as much work as learning things.
Node uses threads internally to make things fast but doesn't expose them to the user. If you are a technical user wondering why node is designed this way then you should 100% read about [the design of libuv](http://nikhilm.github.io/uvbook/), the C++ I/O layer that node is built on top of.
## License

Creative Commons Attribution License (do whatever, just attribute me)
http://creativecommons.org/licenses/by/2.0/
Donate icon is from the [Noun Project](https://thenounproject.com/term/donate/285/)
================================================
FILE: readme.pt-br.md
================================================
# A arte do Node
## Uma introdução ao Node.js
Este documento é destinado à leitores que sabem no mínimo algumas das coisas abaixo:
- Uma linguagem de script como JavaScript, Ruby, Python, Perl, etc. Se você ainda não é um programador então é, provavelmente, mais fácil começar a ler [JavaScript for Cats](http://jsforcats.com/). :cat2:
- Git e Github. Estas são ferramentas de colaboração de código aberto que pessoas da comunidade Node usam para compartilhar módulos. Você só precisa saber o básico. Aqui estão três ótimos tutoriais de introdução. [1](https://github.com/jlord/git-it-electron#readme), [2](http://zachbruggeman.me/github-for-cats/), [3](http://opensourcerer.diy.org/) (em inglês).
Este pequeno livro é um trabalho em progresso. Se você gostar deste livro considere **fazer uma doação** via [gittip](https://www.gittip.com/maxogden/) para que eu possa escrever muito mais.
[](https://www.gittip.com/maxogden/)
## Tabela de Conteúdo
- [Aprenda Node de forma interativa](#aprenda-node-de-forma-interativa)
- [Entendendo Node](#entendendo-node)
- [Módulos do núcleo](#módulos-do-núcleo)
- [Callbacks](#callbacks)
- [Eventos](#eventos)
- [Streams](#streams)
- [Módulos e NPM](#módulos-e-npm)
- [Desenvolvimento no lado do cliente com NPM](#desenvolvimento-no-lado-do-cliente-com-npm)
- [Evoluindo de forma correta](#evoluindo-de-forma-correta)
## Aprenda Node de forma interativa
Como complemento para a leitura deste guia, é super importante que você também inicie o seu editor de texto e comece desde já a escrever alguns códigos em Node. Eu sempre acho que quando acabo de ler algum código em um livro ele nunca realmente é executado, mas aprender a escrever códigos é uma boa maneira para compreender os novos conceitos de programação.
Aqui estão dois grandes tutoriais que você pode instalar no seu computador e permitirá a você aprender o Node de uma forma mais interativa:
### Learn You The Node.js
[Learn You The Node.js](https://github.com/rvagg/learnyounode#learn-you-the-nodejs-for-much-win) é um conjunto de problemas de programação que vai apresentá-lo aos padrões do Node mais comuns. Ele vem como um conjunto de tutoriais interativos de linha de comando.
[](https://github.com/rvagg/learnyounode#learn-you-the-nodejs-for-much-win)
Você pode instalar com o npm:
```
# instalação
npm install learnyounode -g
# inicialização
learnyounode
```
### Stream Adventure
Depois que você finalizar o `learnyounode`, prossiga para o [stream-adventure](https://github.com/substack/stream-adventure) para um conjunto de exercícios a fim de se aprofundar mais ainda no Node.
```
# instalação
npm install stream-adventure -g
# inicialização
stream-adventure
```
[](https://github.com/substack/stream-adventure)
## Entendendo Node
Node.js é um projeto de código aberto feito para te ajudar a escrever programas JavaScript que se comunicam com a rede, sistemas de arquivo ou outros códigos I/O (Entrada/Saida, Leitura/Escrita). Apenas isso! Node é apenas uma simples e estável plataforma I/O que encoraja a construção de módulos sobre ela mesma.
Quais são os exemplos de I/O? Aqui está um diagrama de uma aplicação que foi feita com Node que mostra algumas fontes I/O:

Se você não entende todo os elementos do diagrama está tudo bem. O ponto é mostrar que um simples processo em Node (o hexágono no meio) pode atuar como um agente entre todos os pontos finais de I/O (laranja e roxo representam I/O).
Normalmente construir este tipo de sistema apresentam alguns dos casos:
- Dificuldade para programar, mas robusto e com boa performance (como escrever seus servidores web do zero em C)
- Facilidade para programar, mas não muito robusto/rápido (como quando alguem tenta fazer upload de um arquivo de 5GB e seu servidor trava)
O objetivo do Node é oferecer um balanço entre estes dois: relativamente fácil para entender e usar, e rápido o suficiente para a maioria dos casos.
Node não é nenhuma das coisas a seguir:
- Um framework web (como Rails ou Django, embora possa ser usado para fazer tais coisas)
- Uma linguagem de programação (Node usa JavaScript, mas não é uma linguagem por si só)
Em vez disso, Node é uma coisa no meio. Node é:
- Desenhado para ser simples e relativamente fácil de entender e usar
- Útil para programas baseados no I/O que precisam ser rápidos e/ou manusear várias conexões
Em um nível mais baixo, Node pode ser descrito como uma ferramenta para escrever dois maiores tipos de programas:
- Programas de rede usando os protocolos da web: HTTP, TCP, UDP, DNS e SSL
- Programas que lêem e escrevem dados em sistemas de arquivos e os processos/memória local
O que é um "Programa baseado em I/O"? Aqui estão alguns usos comuns:
- Bancos de dados (ex: MySQL, PostgreSQL, MongoDB, Redis, CouchDB)
- APIs (ex: Twitter, Facebook, Apple Push Notifications)
- Conexões HTTP/WebSocket (usuários de um aplicativo web)
- Arquivos (redimensionador de imagem, editor de vídeo, rádio via internet)
Node processa I/O de modo assíncrono([asynchronous](http://en.wikipedia.org/wiki/Asynchronous_I/O)) que permite manusear várias coisas diferentes simultaneamente. Por exemplo, se você for a um fast food e pedir um cheesburger eles vão pegar seu pedido imediatamente e então fazer você esperar até que o cheesburger esteja pronto. Neste tempo eles podem pegar outros pedidos e começar a fazer os cheesburgers para outras pessoas. Imagine que você tem que esperar na fila, bloqueando todas as outras pessoas na fila enquanto eles preparam o seu hamburger! Isto é chamado **I/O bloqueante** porque todo o I/O (preparamento dos chessburgers) acontece um de cada vez. Node, por outro lado, é **não-bloqueante**, o que significa que pode preparar vários chessburgers de uma só vez.
Aqui estão algumas coisas divertidas feitas de forma fácil com Node graças a sua natureza não-bloqueante:
- Controlar [voos de quadricópteros](http://nodecopter.com)
- Escrever bots para IRC
- Criar [robôs bípedes que andam](http://www.youtube.com/watch?v=jf-cEB3U2UQ)
## Módulos do núcleo
Em primeiro lugar eu recomendo que você instale o Node no seu computador. A maneira mais fácil é visitando [Nodejs.org](http://nodejs.org) e clicar em `install`.
Node tem um pequeno grupo de módulos no seu núcleo (geralmente chamado de *node core*) os quais são apresentados como uma API pública que tem como objetivo escrever programas com eles. Para trabalhar com sistema de arquivos temos o módulo `fs` e para redes existem os módulos `net` (TCP), `http`, `dgram` (UDP).
Em adição aos módulos `fs` e de rede existem outros módulos no núcleo do Node. Existe um módulo para resolver consultas DNS de modo assíncrono chamado `dns`, um módulo para pegar informações específicas do sistema operacional como o *tmpdir* chamado `os`, um módulo para alocação de pedaços binários de memória chamado `buffer`, alguns módulos para parsear urls e caminhos (`url`, `querystring`, `path`), etc. A maioria, se não todos os módulos no núcleo do Node, estão ali para suportar os principais casos de uso do Node: escrever rápidos programas que se comunicam com sistemas de arquivos ou redes.
Node manipula I/O com: callbacks, eventos, streams e módulos. Se você aprender como estas quatro coisas funcionam, então você será capaz de ir dentro de qualquer módulo no núcleo do Node e entender basicamente como interagir com eles.
## Callbacks
Este é o tópico mais importante para entender se você quiser entender como usar o Node. Quase tudo em Node usa callbacks. Eles não foram inventados pelo Node, eles são apenas parte da linguagem JavaScript.
Callbacks são funções executadas de modo assíncrono, ou posteriormente. Ao invés do código ser lido de cima para baixo de forma procedural, programas assíncronos podem executar diferentes funções em diferentes momentos baseando-se na ordem e velocidade em que as funções declaradas anteriormente (como requisições HTTP ou leituras de sistemas de arquivo) forem acontecendo.
A diferença pode ser confusa uma vez que determinar se uma função será assíncrona ou não depende muito do contexto. Aqui está um simples exemplo síncrono, você lê de cima para baixo assim como um livro:
```js
var myNumber = 1
function addOne() { myNumber++ } // define a função
addOne() // roda a função
console.log(myNumber) // resultado: 2
```
Este código define uma função e então na próxima linha chama a função, sem esperar por nada. Quando a função é chamada imediatamente adiciona 1 para a variável number, então podemos esperar que após a chamada da função number seja 2. Esta é a expectativa de uma código síncrono - De cima para baixo sequencialmente.
Node, entretanto, usa principalmente código assíncrono. Vamos usar Node para ler nosso número de um arquivo chamado `number.txt`:
```js
var fs = require('fs') // require é uma função especial fornecida pelo Node
var myNumber = undefined // nós ainda não sabemos o número já que ele está armazenado em um arquivo
function addOne() {
fs.readFile('number.txt', function doneReading(err, fileContents) {
myNumber = parseInt(fileContents)
myNumber++
})
}
addOne()
console.log(myNumber) // resultado: Undefined, já que esta parte do código rodou mais rápido que a função
```
Porque nosso resultado foi `undefined` quando damos *log* no nosso número desta vez? Neste código nós usamos o método `fs.readFile`, que é um método assíncrono. Normalmente coisas que tem que se comunicar com discos rígidos ou redes são assíncronos. Se eles tem que acessar coisas na memória ou fazer algum trabalho na CPU eles serão síncronos. A razão para isso é que I/O é muitoooo muitoooo devagaaaar. Se comunicar com um disco rígido é cerca de 100,000 vezes mais devagar do que se comunicar com a memória (RAM).
Quando nós rodamos este programa todas as funções são automaticamente definidas, mas elas não são executadas imediatamente. Isto é uma coisa fundamental para entender sobre programas assíncronos. Quando `addOne` é chamado fora de `readFile` então executa a próxima coisa que está pronta para executar. Se não tem nada para executar, Node vai esperar as operações pendentes de fs/rede para terminar ou parar de rodar e sair da linha de comando.
Quando `readFile` está pronto para ler o arquivo (isto pode levar de milissegundos para segundos ou minutos dependendo do quão rápido o disco rígido é) ele vai rodar a função `doneReading` e mostrar um erro (se existir algum erro) e o conteúdo do arquivo.
A razão pelo resultado ser `undefined` é que em nenhum lugar do nosso código existe uma lógica que diga para `console.log` esperar até que `readFile` tenha terminado.
Se você tem algum código que tenha que ser executado várias vezes ou depois de um tempo o primeiro passo é colocar o código dentro de uma função. Depois você chama a função quando você quiser rodar aquele código. Dar nomes descritivos as suas funções ajuda.
Callbacks são apenas funções que são executados depois de um tempo. A chave para entender callbacks é perceber que eles são usados quando você não sabe **quando** algum código assíncrono vai terminar, mas você sabe **onde** a operação vai terminar - a última linha da função assíncrona! A ordem de cima à baixo que você declara callbacks não necessariamente importa, apenas a lógica hierárquica de assentamento do código. Primeiro você quebra seu código em funções, e depois usa callbacks para declarar se uma função depende do término de outra função.
O método `fs.readFile` é fornecido pelo Node, é assíncrono e leva um bom tempo para terminar. Considerando o que ele faz: ele tem que ir ao Sistema Operacional, que por sua vez tem que ir ao sistema de arquivos, que está no disco rígido que pode ou não estar rodando à milhares de vezes por minuto. Então ele tem que usar um laser para ler os dados e enviar de volta através das camadas para seu programa JavaScript. Você dá à `readFile` uma função (conhecida como callback) que vai ser chamado assim que receber os dados do sistema de arquivos. Ele bota os dados em uma variável e chama sua função (callback) com aquela variável, nesse caso a variável é chamada `fileContents` porque ela contém os dados do arquivo que foi lido.
Pense no exemplo do fast food no começo deste tutorial. Em muitos restaurantes você pega um número para colocar em sua mesa enquanto você espera sua comida. Isto usa vários callbacks. Eles vão falar ao servidor o que fazer depois que seu cheesburger fique pronto.
Vamos colocar nosso `console.log` em uma função e chamar ela como callback.
```js
var fs = require('fs')
var myNumber = undefined
function addOne(callback) {
fs.readFile('number.txt', function doneReading(err, fileContents) {
myNumber = parseInt(fileContents)
myNumber++
callback()
})
}
function logMyNumber() {
console.log(myNumber)
}
addOne(logMyNumber)
```
Agora a função `logMyNumber` pode ser passada no argumento que vai ser a variável `callback` dentro da função `addOne`. Depois que `readFile` terminar a variável `callback` vai ser invocada (`callback()`). Apenas funções podem ser invocadas, então se você passar alguma coisa que não é uma função vai causar um erro.
Quando uma função é invocada no JavaScript, o código dentro dela será executado imediatamente. Nesse caso, nosso log será executado já que `callback` é a função `logMyNumber`. Lembre que, só porque você *definiu* uma função não significa que ela será executada. Você tem que *invocar* a função para isso acontecer.
Para quebrar o exemplo acima em pedaços, aqui está a linha do tempo dos eventos que acontecem quando rodamos este programa:
- 1: o código é analisado, o que significa que se existir algum erro de sintaxe o programa vai quebrar. Durante esta fase inicial tem 4 coisas que são definidas: `fs`, `myNumber`, `addOne`, e `logMyNumber`. Note que eles estão sendo apenas definidos, nenhuma função foi chamada/invocada ainda.
- 2: quando a última linha do nosso programa é executada `addOne` é invocado, onde `logMyNumber` é passado como `callback`, que é o que queremos que seja chamado quando `addOne` terminar. Isto imediatamente executa o código assíncrono `fs.readFile`. Esta parte do programa leva um tempo para terminar.
- 3: sem nada para fazer, o Node espera até que `readFile` termine. Se existisse alguma outra coisa durante esse tempo, Node poderia fazer o seu trabalho.
- 4: `readFile` termina e chama o callback, `doneReading`, que incrementa o número e imediatamente invoca a função callback de `addOne`, `logMyNumber`.
Talvez a parte mais confusa de programar com callbacks é que funções são apenas objetos que podem ser armazenadas em variáveis e passadas no programa com diferentes nomes. Dar um simples e descritivo nome para suas variáveis é importante para fazer seu código legível para outras pessoas. Geralmente, falando em programas Node, quando você vê uma variável como `callback` ou `cb` você sabe que é uma função.
Você pode ter ouvido os termos "programação evencionada" ou "ciclo de eventos". Eles se referem a maneira que `readFile` é implementado. O Node roda primeiro a operação `readFile` e então espera por `readFile` para enviar um evento dizendo que está completo. Enquanto espera, o Node pode checar outras coisas. Dentro do Node está uma lista de coisas que são executadas mas não foram reportadas de volta ainda, então o Node faz um loop contínuo na lista para checar se elas terminaram. Depois que eles terminam eles são "processados" (ex.: callbacks que dependem desse término vão ser invocados).
Aqui temos a versão de um pseudocódigo do exemplo acima:
```js
function addOne(thenRunThisFunction) {
waitAMinuteAsync(function waitedAMinute() {
thenRunThisFunction()
})
}
addOne(function thisGetsRunAfterAddOneFinishes() {})
```
Imagine que você tem 3 funções assíncronas `a`, `b` e `c`. Cada uma leva um minuto para rodar e quando terminadas chamam um callback (que é passado no primeiro argumento). Se você disser para o Node: 'comece executando "a", depois execute "b" quando "a" terminar, e então execute "c" quando "b" terminar', isso ficaria assim:
```js
a(function() {
b(function() {
c()
})
})
```
Quando este código é executado, `a` vai iniciar automaticamente, então, um minuto depois ele vai terminar e chamar `b`, e um minuto depois ele vai terminar e chamar `c` e, finalmente, 3 minutos depois o Node vai parar o código já que não tem mais nada para fazer. Definitivamente, existem formas mais elegantes de escrever o código acima, mas o ponto é que se você tiver um código que tem que esperar outro código assíncrono terminar então você expressa esta dependência colocando este código em funções que são passadas como callbacks.
A forma como o Node trabalha requer que você pense de uma forma não-linear. Considerando esta lista de operações:
```
ler um arquivo
processar esse arquivo
```
Se você precisar transformar em pseudocódigo ficaria assim:
```
var file = readFile()
processFile(file)
```
Este tipo de código linear (passo-a-passo, em ordem) não é a maneira que Node trabalha. Se este código fosse executado então `readFile` e `processFile` iriam executar ao mesmo tempo. Isto não faz sentido já que `readFile` vai levar um tempo para completar. Ao invés disso você precisa expressar que `processFile` depende de `readFile`. Este é o trabalho dos callbacks! E por causa da maneira que JavaScript trabalha você pode escrever esta dependência de várias maneiras diferentes:
```js
var fs = require('fs')
fs.readFile('movie.mp4', finishedReading)
function finishedReading(error, movieData) {
if (error) return console.error(error)
// faça algo com movieData
}
```
Mas você támbem pode estruturar o seu código dessa maneira, e ainda assim vai funcionar:
```js
var fs = require('fs')
function finishedReading(error, movieData) {
if (error) return console.error(error)
// faça algo com movieData
}
fs.readFile('movie.mp4', finishedReading)
```
Ou até mesmo assim:
```js
var fs = require('fs')
fs.readFile('movie.mp4', function finishedReading(error, movieData) {
if (error) return console.error(error)
// faça algo com movieData
})
```
## Eventos
No Node, se você requisitar o módulo [events](http://nodejs.org/api/events.html), você pode utilizar o também chamado "emissor de evento" que o próprio Node utiliza para todas as suas APIs a fim de emitir coisas.
Eventos são padrões comuns na programação, para conhecer melhor procure por ['observer pattern'](http://en.wikipedia.org/wiki/Observer_pattern) ou 'pub/sub' (publicar/assinar). Assim como callbacks são uma relação de um-para-um entre algo que espera pelo callback e outra parte que chama o callback, eventos seguem o mesmo padrão com exceção de que eles são uma API de muitos-para-muitos.
A forma mais fácil de pensar a respeito de eventos é que eles permitem a você assinar as coisas. Você pode dizer "quando X fazer Y", enquanto que com um simples callbacks é "faça X, então Y".
Aqui temos casos comuns para utilizar eventos ao invés de simples callbacks:
- Uma sala de chat onde você tem um canal de mensagens com muitos ouvintes.
- Servidor de um jogo que necessita saber quando os players se conectam, desconectam, movem-se, atiram ou pulam.
- Mecânismo de um jogo onde você quer permitir que os desenolvedores de jogos disparem eventos como: `.on('jump', function() {})`.
- Um servidor web de baixo nível que quer expor uma API para criar facilmente um gancho para os eventos que acontecem como `on ('incomingRequest')` ou `on ('SERVERERROR')`.
Se você tentar escrever um servidor de chat que se conecte usando apenas callbacks ele vai se parecer com isso:
```js
var chatClient = require('my-chat-client')
function onConnect() {
// exibe a UI quando conectar-se
}
function onConnectionError(error) {
// exibe um erro para o usuário
}
function onDisconnect() {
// avisa ao usuario que ele foi desconectado
}
function onMessage(message) {
// exibe a mensagem na UI da sala
}
chatClient.connect(
'http://mychatserver.com',
onConnect,
onConnectionError,
onDisconnect,
onMessage
)
```
Como você pode ver, isto é realmente pesado pois você tem que passar todas as funções em uma ordem especifica para a função `.connect`. Escrevendo isso com eventos irá se parecer com isso:
```js
var chatClient = require('my-chat-client').connect()
chatClient.on('connect', function() {
// exibe a UI quando conectar-se
})
chatClient.on('connectionError', function() {
// exibe um erro para o usuário
})
chatClient.on('disconnect', function() {
// avisa ao usuario que ele foi desconectado
})
chatClient.on('message', function() {
// exibe a mensagem na UI da sala
})
```
Esta abordagem é bastante similar a utilização com callbacks-puros, mas essa abordagem introduz o método `.on` onde atrela um callback a um evento. Isso significa que você pode escolher quais eventos deseja assinar a partir do `chatClient`. Você pode assinar o mesmo evento diversas vezes com diferentes callbacks:
```js
var chatClient = require('my-chat-client').connect()
chatClient.on('message', logMessage)
chatClient.on('message', storeMessage)
function logMessage(message) {
console.log(message)
}
function storeMessage(message) {
myDatabase.save(message)
}
```
## Streams
Logo no início do projeto do Node, as APIs de arquivos de sistema e redes tiveram os seus próprios padrões de separação para lidar com a streaming de I/O. Por exemplo, arquivos em um sistema de arquivos tem propriedades que se chamam "descritores de arquivo" então o módulo `fs` teve uma lógica adicional enquanto o módulo de rede não teve esse conceito adicionado. Apesar de diferenças menores na semâtica como esta, em um nível fundamental ambos os grupos de código tem uma grande quantidade de funcionalidades duplicadas onde fazem a leitura de dados na entrada e saida. O time que esta trabalhando no Node percebeu que seria confuso ter que aprender dois conjuntos de semântica, essencialmente, fazendo a mesma coisa, por isso fizeram uma nova API chamada `Stream` e tudo o que demanda rede e sistema de arquivos usa ela como base.
O ponto principal do Node é facilitar a comunicaçãoo com o sistema de arquivos e redes através de um padrão que é utilizado em todos os lugares. A boa notícia é que a maioria dos padrões como esse (há apenas alguns) foram descobertos até este ponto e terão poucas mudanças mesmo que seja quase improvável que isso aconteça no futuro.
Já existem duas grandes fontes que você pode utilizar para aprender a respeito de Streams no Node. Uma é o *stream-adventure* (veja a seção [Aprenda Node de forma interativa](#aprenda-node-de-forma-interativa)) e a outra é uma referência chamada *Stream Handbook*.
### Stream Handbook
O [stream-handbook](https://github.com/substack/stream-handbook#introduction) é um guia, similar a este, que contém referências para tudo o que você quer saber a respeito de Streams.
[](https://github.com/substack/stream-handbook)
## Módulos e NPM
O núcleo do Node é composto de cerca de duas dezenas de módulos, alguns com níveis mais baixos como `events` e `streams`, e outras de níveis mais alto como `http` e `crypto`.
Este projeto é intencional. O núcleo do Node foi desenvolvido para ser pequeno e os módulos no núcleo devem focar no fornecimento de ferramentas para trabalhar com protocolos e formatos comuns de I/O de maneira multiplataforma.
Para todo o restante, existe o [NPM](https://npmjs.org/). Qualquer um pode criar um novo módulo para o Node que adicione alguma funcionalidade e publicá-lo no NPM. No momento em que escrevo isso, existem 34.000 módulos no NPM.
### Como encontrar um módulo
Imagine que você está tentando converter arquivos PDF em arquivos TXT. A melhor forma para iniciar esta busca é com `npm search pdf`:

Há uma tonelada de resultados! NPM é bastante popular e normalmente você vai ser capaz de encontrar várias soluções possíveis. Se você passar por cada módulo e filtrar os resultados em um conjunto mais estreito (filtrando as coisas como módulos de geração de PDF), você vai acabar com estes resultados:
- [hummus](https://github.com/galkahana/HummusJS/wiki/Features) - c++ pdf manipulator
- [mimeograph](https://github.com/steelThread/mimeograph) - api on a conglomeration of tools (poppler, tesseract, imagemagick etc)
- [pdftotextjs](https://npmjs.org/package/pdftotextjs) - wrapper around [pdftotext](https://en.wikipedia.org/wiki/Pdftotext)
- [pdf-text-extract](https://npmjs.org/package/pdf-text-extract) - another wrapper around pdftotext
- [pdf-extract](https://npmjs.org/package/pdf-extract) - wrapper around pdftotext, pdftk, tesseract, ghostscript
- [pdfutils](https://npmjs.org/package/pdfutils) - poppler wrapper
- [scissors](https://npmjs.org/package/scissors) - pdftk, ghostscript wrapper w/ high level api
- [textract](https://npmjs.org/package/textract) - pdftotext wrapper
- [pdfiijs](https://github.com/fagbokforlaget/pdfiijs) - pdf to inverted index using textiijs and poppler
- [pdf2json](https://github.com/modesty/pdf2json/blob/master/readme.md) - pure js pdf to json
Diversos módulos possuem sobreposição de funcionalidade, mas as atuais APIs alternativas e a maioria delas requer dependências externas (como o `apt-get install poppler`).
Aqui estão algumas maneiras diferentes de interpretar os módulos:
- `pdf2json` é o único que está escrito em JavaScript puro, o que significa que é mais fácil de instalar, especialmente em dispositivos de baixa potência, como o Raspberry Pi ou no Windows, onde o código nativo pode não ser multiplataforma;
- módulos como `mimeograph`, `hummus` e `pdf-extract` onde cada um combina vários módulos de nível inferior para expor uma API de alto nível;
- uma série de módulos parecem tomar como base a linha de comando unix do `pdftotext`/`poppler`
Vamos comparar as diferenças entre `pdftotextjs` e `pdf-text-extract`, ambos estão contidos no utilitário `pdftotext`.

Ambos:
- foram atualizados recentemente
- possuem repositórios github "linkados" (isto é muito importante!)
- posuem READMEs
- possuem, ao menos, um número considerável de pessoas o instalando toda semana
- são "livremente" licenciados (qualquer um pode usar)
Olhando apenas para os arquivos `package.json` + módulo de estatísticas, é difícil obter uma sensação sobre qual pode ser a escolha certa. Vamos comparar os READMEs:

Ambos possuem descrições simples, emblemas para CI, instruções de instalação, exemplos claros e instruções para a execução dos testes. Otimo! Mas, qual é que vamos usar? Vamos comparar o código:

`pdftotextjs` possue cerca de 110 linhas, e `pdf-text-extract` cerca de 40 linhas, mas ambos, essencialmente, resumem-se a esta linha:
```
var child = shell.exec('pdftotext ' + self.options.additional.join(' '));
```
Será que isto faz um melhor que o outro? Difícil dizer! É realmente importante "ler" o código e fazer as suas próprias conclusões. Se você encontrar um módulo que você gosta, use `npm star modulename` para dar um *feedback* sobre os módulos que você teve uma experiência positiva com ele.
### Fluxo de Desenvolvimento Modular
NPM é diferente da maioria dos gerenciadores de pacotes já que ele instala módulos em uma pasta dentro de outros módulos já existentes. A frase anterior pode não fazer sentido agora, mas é a chave para o sucesso do NPM.
Muitos gerenciadores de pacotes instalam as coisas globalmente. Por exemplo, se você executar `apt-get install couchdb` no Linux Debian ele vai tentar instalar a última versão estável do CouchDB. Se você estiver tentando instalar o CouchDB como dependência de um Software e este precisa de uma versão anterior do CouchDB, você terá de desinstalar a nova versão do CouchDB e assim instalar a versão anterior. Você não pode ter duas versões do CouchDB instaladas pois o Debian só sabe como instalar as coisas em um local somente.
Não é apenas o Debian que faz isso. A maioria dos gerenciadores de pacotes de linguagem de programação funciona dessa maneira também. Para organizar o problema das dependências globais descrito acima, foram desenvolvidos ambientes virtuais como [virtualenv](http://docs.python-guide.org/en/latest/dev/virtualenvs.html) para o Python ou [bundler](http://bundler.io/) para o Ruby. Eles apenas dividem o ambiente em muitos ambientes virtuais, um para cada projeto, mas dentro de cada ambiente as respectivas dependências continuam instaladas de modo global. Os ambientes virtuais nem sempre resolvem o problema, às vezes eles só o multiplicam através da inclusão de camadas adicionais de complexidade.
Com o NPM, a instalação de módulos globais é um anti-padrão. Assim como você não deve usar as variáveis globais em seus programas em JavaScript você também não deve instalar os módulos globais (a menos que você precise de um módulo com um binário executável a aparecer em seu `PATH` global, mas nem sempre você precisa fazer isso - mais sobre isso depois).
#### Como o `require` funciona.
Quando você chama o `require('algum_modulo')` no Node, isto é o que acontece:
1. se o arquivo chamado `algum_modulo.js` existir no diretório atual o Node vai carregá-lo, do contrário:
2. o Node vai procurar no diretório atual pela pasta `node_modules` com `algum_modulo` nele
3. caso não encontre, ele fará o mesmo processo no diretório pai
Este ciclo será efetuado até o Node chegar no diretório raiz do sistema de arquivos, até que ele comece a verificar os diretórios dos módulos globais (ex.: `/usr/local/node_modules` no Mac) e, mesmo assim, se `algum_modulo` não for encontrado, será lançada uma exceção.
Aqui temos um exemplo prático:

Quando o diretório de trabalho atual é `subsubfolder` e `require('foo')` é chamado, o Node vai procurar pelo diretório chamado `subsubfolder/node_modules`. Neste caso, não será encontrado - o diretório foi nomeado incorretamente como `my_modules`. Então, o Node vai procurar no diretório pai e tentar novamente, o que significa que ele vai procurar no diretório `subfolder_B/node_modules` , o qual também não existe. Já a terceira tentativa funciona perfeitamente, pois `folder/node_modules` existe e possui uma pasta chamada `foo` dentro dela. Se `foo` não estivesse neste local, o Node continuaria a sua busca no diretório pai do diretório atual onde a busca está sendo feita.
Observe que se chamarmos do diretório `subfolder_B` o Node nunca vai encontar `subfolder_A/node_modules`, ele apenas pode visualizar `folder/node_modules` e o que estiver nos diretórios acima dele.
Um dos benefícios da abordagem do NPM é que os módulos podem instalar seus módulos dependentes em versões específicas de trabalho conhecidos. Neste caso, o módulo `foo` é muito popular - existem três cópias dele, cada um instalado dentro de um diretório parente. A razão para isto é que cada módulo parente necessita de uma versão diferente de `foo`, para exemplificar: `folder` precisa de `foo@0.0.1`, `subfolder_A` precisa de `foo@0.2.1` e assim por diante.
Isto é o que acontece quando consertamos o nome do diretório `my_modules` colocado equivocadamente para o nome correto `node_modules`:

Para testar qual módulo foi carregado pelo node, você pode utilizar o comando `require.resolve('algum_modulo')`, o que vai mostrar o caminho para o módulo que o Node encontrar como resultado no procedimento de busca através dos diretórios. O `require.resolve` pode ser útil para fazer uma verificação mais rígida quando você quer ter a certeza de que um módulo está sendo carregado - às vezes há uma outra versão do mesmo módulo mais perto de seu diretório de trabalho atual do que aquele que você pretende carregar.
### Como criar um módulo
Agora que você já sabe como encontrar os módulos e fazer as suas requisições, você pode começar a escrever os seus próprios módulos.
#### O módulo mais simples possível
Os módulos do Node são radicalmente leves. Aqui está uma das possibilidades mais simples para um módulo no Node:
`package.json`:
```js
{
"name": "number-one",
"version": "1.0.0"
}
```
`index.js`:
```js
module.exports = 1
```
Por padrão, o Node tenta carregar `module/index.js` quando você faz um `require('module')`, qualquer outro nome de arquivo não vai funcionar a menos que você defina o campo `main` no `package.json` e aponte para ele.
Coloque ambos os arquivos em uma pasta chamada `number-one` (o `id` em `package.json` deve coincidir com o nome da pasta) e você terá um módulo Node para trabalhar.
Chamando a função `require('number-one')` será retornado o valor de qualquer `module.exports` que estiver definido dentro do módulo:

Uma forma ainda mais rápida para criar um módulo é executando os seguintes comandos:
```sh
mkdir my_module
cd my_module
git init
git remote add git@github.com:yourusername/my_module.git
npm init
```
Executando `npm init` será criado um manifesto JSON válido chamado `package.json` para você e se você executá-lo em um repositório `git` existente, será definido um campo `repositories` dentro do `package.json` automaticamente!
#### Adicionando dependências
Um módulo pode listar outros módulos a partir do NPM ou Github no campo `dependencies` do arquivo `package.json`. Para instalar o módulo `request` como uma nova dependência e automaticamente adicioná-la ao `package.json` é preciso executar o seguinte comando a partir do seu diretório raiz:
```sh
npm install request --save
```
Isto vai instalar uma cópia de `request` na pasta mais próxima do `node_modules` e fazer o nosso `package.json` se parecer assim:
```
{
"id": "number-one",
"version": "1.0.0",
"dependencies": {
"request": "~2.22.0"
}
}
```
Por padrão, `npm install` vai pegar a versão mais atual publicada do módulo.
## Desenvolvimento no lado do cliente com NPM
Um equívoco comum sobre NPM é que uma vez que tem "Node" no nome que deve ser usado apenas para os módulos de JS do lado do servidor. Isto é completamente falso! O NPM está realmente para modulos empacotados do Node, por exemplo, módulos que o Node empacota para você. Os próprios módulos podem ser o que você quiser - eles são apenas uma pasta de arquivos contidos em um arquivo `tar.gz`, e um arquivo chamado `package.json` que declara a versão do módulo e uma lista de todos os módulos que são dependências deste módulo (bem como os respectivos números de versão para a versão de trabalho ficar instalado automaticamente). As dependências deste do módulo são apenas módulos, e estes módulos podem ter dependências, etc, etc, etc.
O [browserify](http://browserify.org/) é um utilitário escrito em Node que tenta converter qualquer módulo do Node em um código que possa ser executado em qualquer *browser*. Nem todos os módulos funcionam (navegadores não podem fazer determinadas coisas como hospedar um servidor HTTP), mas muitos módulos no NPM "vão" funcionar.
Para testar o NPM no *browser*, você pode utilizar o [RequireBin](http://requirebin.com/), que é um app que eu fiz e aproveita as vantagens do [Browserify-CDN](https://github.com/jesusabdullah/browserify-cdn), que utiliza o *browserfy* por debaixo dos panos, mas retorna uma saída através do HTTP (em vez da linha de comando - que é a forma como é normalmente usado o browserify).
Tente colocar este código dentro do *RequireBin* e pressione o botão *preview*:
```js
var reverse = require('ascii-art-reverse')
// makes a visible HTML console
require('console-log').show(true)
var coolbear =
" ('-^-/') \n" +
" `o__o' ] \n" +
" (_Y_) _/ \n" +
" _..`--'-.`, \n" +
" (__)_,--(__) \n" +
" 7: ; 1 \n" +
" _/,`-.-' : \n" +
" (_,)-~~(_,) \n"
setInterval(function() { console.log(coolbear) }, 1000)
setTimeout(function() {
setInterval(function() { console.log(reverse(coolbear)) }, 1000)
}, 500)
```
Ou verifique um [exemplo mais completo](http://requirebin.com/?gist=6031068) (fique a vontade para modificar o código e ver o que acontece):
[](http://requirebin.com/embed?gist=6031068)
## Evoluindo de forma correta
Como todo boa ferramenta, o Node é adequado para certos casos de uso. Por exemplo: Rails, o popular web framework, é ótimo para modelar complexas [lógicas de negócios](http://en.wikipedia.org/wiki/Business_logic).
Exemplo: usando código para representar a vida em um plano objetivado que vivemos físicamente como contas, empréstimos, itinerários e inventários. Embora tecnicamente seja possivel fazer o mesmo utilizando o Node, haveriam desvantagens claras sabendo que o Node é projetado para resolver problemas de I/O e não sabe muito a respeito de "lógica de negócio". Cada ferramenta tem um foco para resolver diferentes problemas. Esperamos que este guia ajude-o a ganhar uma compreensão intuitiva dos pontos fortes do Node para que você saiba quando ele será útil.
### O que está fora do escopo do Node?
Fundamentalmente o Node é somente usado como uma ferramenta para gerenciar I/O ao redor do sitema de arquivos e redes, ele deixa outras funcionalidades mais bonitas com módulos de terceiros. Aqui são algumas das coisas ques estão **fora** do escopo do Node:
#### Web frameworks
Existe uma boa quantidade de web frameworks construidos em cima do node (framework é um pacote que tenta resolver um problema de alto nível e problemas similares à modelagem de lógica de negócios), mas o Node não é um framework para web. Frameworks web são escritos para serem utilizados no Node e nem sempre tomam o mesmo tipo de decisões sobre a adição de complexidade, abstração e compreensão que o Node faz e podem ter outras prioridades.
#### Sintaxe da linguagem
O Node usa JavaScript e não muda nada sobre isso. Felix Geisendörfer tem um belo conteúdo escrito sobre o "Guia de estilo do Node" [aqui](https://github.com/felixge/node-style-guide).
#### Abstração da linguagem
Quando possivel, o Node vai usar a maneira mais simples para fazer algo. Código mais "bonito" faz do seu JavaScript mais complexo e compromissado com vantagens e desvantagens. Programar é difícil, especialmente em JS onde você tem 1000 soluções para o mesmo problema! Essa é a principal razão para o Node optar pela simplicidade sempre que possível e que pode ser uma opção universal. Se você está resolvendo um problema complexo e está insatisfeito com o modo como o Node implementa as coisas com "soluções de JS com gosto de baunilha", sinta-se livre para resolver isso dentro do seu app ou módulo usando quaisquer abstrações que você preferir.
Um grande exemplo é como o Node usa os callbacks. Logo no início foi experimentado a característica chamada *promises* que adicionava algumas funcionalidades para fazer o código assíncrono parecer mais linear. Ele foi levado para o fora do núcleo do Node por algumas razões:
- eles são mais complexos que callbacks
- ele podem ser implementados na *userland* (distriuído no npm como módulo de terceiros)
Considere uma das mais universais e básicas ideias que o Node faz: ler um arquivo. Onde você lê um arquivo e precisa saber onde os erros acontecem, como quando o disco rígido morre no meio da sua leitura. Se Node tivesse *promises* todo mundo teria que criar um *branch* como o código abaixo:
```js
fs.readFile('movie.mp4')
.then(function(data) {
// faz algo com os dados
})
.error(function(error) {
// manipula o erro
})
```
Isso adiciona uma complexidade desnecessária. No lugar de duas funções separadas o Node somente usa uma única função de callback. Aqui temos as regras:
- Quando não existir erros passe *null* como primeiro argumento.
- Quando existir um erro, passar ele como primeiro argumento.
- O restante dos argumentos são usados para qualquer coisa (usualmente dados ou respostas, já que na maior parte do tempo o Node está lendo ou escrevendo coisas).
Por isso, o Node usa o estilo de callback:
```js
fs.readFile('movie.mp4', function(err, data) {
// manipula erro, faz algo com os dados
})
```
#### Soluções baseadas em Threads/fibers/non-event
Nota: Se você não sabe o que isso tudo significa você terá uma facilidade maior com o tempo para aprender como o Node funciona, visto que desaprender coisas leva o mesmo tempo que aprender.
O Node usa *threads* internamente para fazer coisas de uma forma rápida mas não expõe isso ao usuário. Se você é um usuário técnico e está perguntando-se o porquê dele ser projetado desta maneira, esta leitura é 100% sobre [o design de libuv](http://nikhilm.github.com/uvbook/), que onde a camada de I/O feita em C++ e pela qual o Node é concebido.
## Licença

Creative Commons Attribution License (faça o que quiser, apenas dê os créditos)
http://creativecommons.org/licenses/by/2.0/
Donate icon is from the [http://thenounproject.com/noun/donate/#icon-No285](Noun Project)
================================================
FILE: readme.ru.md
================================================
# Поэзия Ноды
## Введение в Node.js
Данный материал предназначен для читателей, которые уже имеют представление о:
- скриптовых языках типа JavaScript, Ruby, Python, Perl и других. Если вы только начинаете программировать, то вам стоит начать с прочтения [JavaScript for Cats](http://jsforcats.com/). :cat2:
- git и github. Эти инструменты для совместной работы широко используются в сообществе, чтобы делиться своими модулями. Вам достаточно знать хотя бы их основы. По ним есть отличные самоучители для новичков:
[1](https://github.com/jlord/git-it-electron#readme), [2](http://ericsteinborn.com/github-for-cats/#/), [3](http://opensourcerer.diy.org/)
## Оглавление
- [Изучи Ноду интерактивно](#learn-node-interactively)
- [Путь к пониманию Ноды](#understanding-node)
- [Базовые модули](#core-modules)
- [Колбэки] [Callbacks](#callbacks)
- [События / Событийная модель](#events)
- [Потоки в Ноде](#streams)
- [Модули и npm. Экосистема Ноды](#modules)
- [Разработка клиентской части с npm](#client-side-development-with-npm)
- [Правильный выбор инструмента](#going-with-the-grain)
От переводчика
Несколько замечаний по переводу
В тексте будут встречаться английские слова и словосочетания. Такие термины я оставлял в скобках, чтобы читатель по мере прочтения привыкал к терминологии Ноды, и не привязывался к русским формулировкам, зачастую абсолютно без образным. Как правило это ключевые понятия типа "hard drive" или "event loop", которые опытный разработчик должен знать и так. А для начинающих так будет проще освоиться в тексте, чтобы у них не возникало двусмысленностей при чтении, когда одну и ту же вещь (образ) называют разными именами.
В некоторых местах я отклонялся от оригинального текста, меняя формулировку или же просто оставляя его без перевода.
Часто это было по двум причинам
1. Я не понимал что хотел сказать автор и как перевести так, чтобы сохранился тот смысл, который он хотел передать
2. Я не видел большого смысла в написанном
С опытом вы всё чаще будете употреблять английские слова, произнося их по-русски, сокращая и даже коверкая. Со временем у вас выработается свой сленг, на котором вам будет удобно разговаривать с коллегами. Это нормально. Главное передать словом тот образ\суть, предмет разговора, а не вспоминать заученные формулировки на родном языке.
Благодарю авторов этой статьи http://frontender.info/art-of-node/ . В своем переводе я часто обращался к ней, чтобы сравнить или лучше понять смысл написанного.
Это также перевод этой статьи, но авторы не стали выкладывать её на гитхаб.
## Изучи Ноду интерактивно
В дополнение к чтению, очень важно параллельно писать код. Так вы скорее проникнетесь духом ноды и вникнете в её суть. Читать код в книге важно и нужно, но обучение через само написание кода - это ещё более лучший способ познания новых принципов программирования.
### NodeSchool.io
[NodeSchool.io](http://nodeschool.io/) серия открытых интерактивных воркшопов, по которым можно обучиться основным принципам Ноды.
[Learn You The Node.js](https://github.com/workshopper/learnyounode#learn-you-the-nodejs-for-much-win) представляет собой вступительный воркшоп NodeSchool.io. Здесь собраны несколько задач, решение которых поможет тебе усвоить основные принципы построения программ для Ноды. Устанваливается как консольная утилита.
[](https://github.com/rvagg/learnyounode#learn-you-the-nodejs-for-much-win)
Устанавливается через npm:
```
# install
npm install learnyounode -g
# start the menu
learnyounode
```
## Путь к пониманию Ноды
Node.js - опенсорсный проект, сделанный чтобы помочь тебе писать программы для работы с сетью, файловыми системами и другими I/O (input/output, reading/writing) на языке JavaScript. Вот и всё! Это простая и стабильная I/O платформа в которой удобно создавать свои модули.
Какие ещё есть примеры использования ввода/вывода (далее I/O)? Здесь показана схема приложения, к-ое я делал на Ноде; на ней видно какие могут быть I/O источники:

Если ты не знаешь все источники представленные на схеме, ничего страшного. Суть в том, чтобы показать, что один единственный процесс Ноды (шестигранник в центре) может выполнять роль брокера (диспетчера) между разными конечными пунктами (endpoints) I/O (оранжевым и фиолетовым обозначены каналы ввода/вывода).
Обычно, построение систем такого вида складывается по одному из путей:
- сложно для написания, но в результате получается супер-быстрая система (подобно написанию своих веб-серверов на чистом C)
- просты в написании но сильно страдает в скорости работы (особенно, когда кто-то пытается отправить на сервер 5Гб файл и твой сервер падает)
Задача Ноды - сохранить равновесие при достижении двух целей: быть достаточно простым для понимания и использования и настолько же быстрым для решения большинства задач.
Нода не является:
- веб-фреймворком (вроде Rails или Django, хотя и может использоваться для создания подобных вещей)
- языком программирования (Нода использует JS, но сама Нода языком НЕ является)
Нода - нечто среднее, можно сказать, что Нода:
- Сделана чтобы быть простой для понимания и использования
- Удобной при создании I/O программ, которые должны работать быстро и оставаться устойчивой к высоким нагрузкам
На более низком уровне, Ноду можно назвать инструментом для написания двух типов программ:
- Сетевые программы, использующие протоколы веба: HTTP, TCP, UDP, DNS и SSL
- Программы, для чтения и записи данных в файловую систему (далее ФС) или локальные процессы/память
Что означает "программы для I/O" ("I/O based program")? Рассмотрим несколько основых источников Ввода/Вывода (I/O sources):
- Базы данных (MySQL, PostgreSQL, MongoDB, Redis, CouchDB)
- Внешние API (Twitter, Facebook, Apple Push Notifications)
- HTTP/WebSocket соединения (от пользователей веб-приложений)
- Файлы (сжатие изображений, редактирование видео, интернет-радио)
Нода выполняет операции ввода/вывода способом, к-ый называют асинхронным [asynchronous](https://en.wikipedia.org/wiki/Asynchronous_I/O). Такой способ позволяет ей выполнять много разных операций одновременно (simultaneously). Приведу небольшой пример для большего понимания. Например, зайдя в какой-нибудь фаст-фуд и заказав чизбургер, ваш заказ примут *сразу*, и после *небольшой задержки* ваш заказ будет готов. Пока вы ждете, они могут принимать другие заказы и начать готовить чизбургеры для других людей. А теперь представьте ситуацию, когда остальным людям в очереди приходится ждать пока вам не принесут чизбургер. Они даже не смогут сделать заказ, пока вам его не приготовят! Технически такое поведение называется **блокирующая очередь**, ведь все операции ввода/вывода (по приготовлению чизбургеров) происходят строго по одной в 1 момент времени. Нода же, наоборот, реализует механизм **неблокирующей очереди**, что позволяет готовить много чизбургеров одновременно.
На Ноде такие вещи можно реализовать довольно легко, благодаря её неблокирующей сущности:
- Механизм управления [летающими квадракоптерами](http://www.nodecopter.com/)
- Написать IRC чат-ботов
- Создать [ходячих роботов](https://www.youtube.com/watch?v=jf-cEB3U2UQ)
## Базовые модули (Core modules)
Во-первых, установите Ноду себе на компьютер. Брать её лучше отсюда [nodejs.org](http://nodejs.org)
У ноды есть небольшая группа базовых модулей (которую обычно называют одним термином 'Ядро Ноды' ('node core')), которые предоставлены, как внешний API для написания программ. Каждый модуль предназначен для своих целей: для работы с файловой системой есть модуль 'fs', для работы с сетями `net` (TCP), `http`, `dgram` (UDP).
Помимо модуля `fs` и сетевых модулей, есть и другие базовые модули. Для асинхронной работы с DNS-запросами есть модуль `dns`, `os` - для получения данных об ОСи, для выделения бинарных фрагентов памяти (a module for allocating binary chunks of memory called) есть `buffer`, модули для различного рода парсинга урлов, путей к файлам и вообще (`url`, `querystring`, `path`). Большинство из базовых модулей, если не все, служат для одной общей цели - написание быстрых (!) программ для работы с ФС или сетью.
Нода обрабатывает I/O-операции используя: колбэки, события, потоки и модули. Если ты знаешь как они работают, то сможешь разобраться в любом базовом модуле и понять как его правильно использовать.
## Колбэки (Callbacks)
Это, пожалуй, самая важная часть всего гайда. Если хочешь понять как работает Нода - придется разобраться с колбэками. Колбэки используются в Ноде повсюду; это не открытие Ноды, они лишь часть языка JavaScript.
Итак, начнем с определения. Колбэки - функции, к-ые вызываются не сразу, по мере выполнения основного кода, а асинхронно (asynchronously), т.е. их *выполнение* (invoking) будет отложено. В отличие от привычного процедурного стиля написания и выполнения кода **сверху вниз** (top to bottom), асинхронные программы могут выполнять свои функции непоследовательно (не в порядке их написания), учитывая скорость выполнения предыдущих функций, например http-запросов или чтения с диска.
Поначалу такое отличие попросту сбивает с толку. Действительно, бывает трудно определить заранее, будет ли функция выполняться асинхронно или нет - во многом это зависит от контекста её выполнения. Разберем простой пример синхронного выполнения, где код будет выполняться последовательно сверху вниз:
```js
var myNumber = 1
function addOne() { myNumber++ } // определяем функцию
addOne() // выполняем функцию
console.log(myNumber) // 2
```
В коде определяется функция и на след строке происходит её вызов, без задержек и пауз. Когда функция вызывается, myNumber *сразу* увеличится на 1. Мы уверены, что после вызова функции число станет равным 2. Это и есть предсказуемость синхронного кода - он всегда выполняется последовательно сверху вниз.
Нода же часто использует асинхронную модель выполнения кода. Давайте с помощью Ноды прочитаем число из файла `number.txt` (файл находится на диске, а значит будем использовать модуль `fs` - прим. перев.):
```js
var fs = require('fs') // подключение модуля для работы с ФС
var myNumber = undefined // пока мы не знаем какое число записано в файле
function addOne() {
fs.readFile('number.txt', function doneReading(err, fileContents) {
myNumber = parseInt(fileContents)
myNumber++
})
}
addOne()
console.log(myNumber) // undefined -- эта строка выполнится до того, как будет прочитан файл!
```
Почему же после вызова функции мы получили `undefined`? Обратите внимание, в коде мы используем асинхронный метод `fs.readFile`. Обычно, такие функции, где идут операции чтения-записи на диск или работа с сетью, делают асинхронными. Когда же требуется обратиться к памяти напрямую или поиспользовать возможности процессора, то функции делают синхронными. Дело в том, что операции I/O невероятно медленные (reallyyy reallyyy sloowwww) (это относится не только к Ноде но и ко всем языкам и технологиям - прим. перев). Стоит сказать, что чтение с диска (hard drive) происходит медленнее чем из памяти (RAM) примерно в 100k раз.
Когда мы запустим эту программу, определение функций произойдет немедленно, но такая быстрота не относится к скорости их выполнения. Это ключевой принцип для понимания асинхронного программирования. Когда произойдет вызов `addOne` она следом запустит функцию `readFile`, но не будет ждать окончания её работы, а перейдет к следующей задаче. Если Ноде больше нечего выполнять она будет просто ждать окончания IO-операций чтобы закончить работу и выйти.
Далее, когда `readFile` прочитает файл (это может занять некоторое время от нескольких миллисекунд до нескольких секунд или даже минут, в зависимости от того как быстро происходит чтение с диска), следом будет выполняться функция `doneReading`, которая и выдаст содержимое файла (если чтение прошло успешно) или ошибку.
В нашей программе мы получили на выходе `undefined` потому что в нашем коде нет никаких явных указаний функции `console.log` дождаться окончания выполнения `readFile` перед тем как выводить число.
Если вы хотите, чтобы какой-то код гарантированно выполнился последовательно, сперва поместите этот код в функцию! Только после этого ты сможешь вызвать функцию (выполнить блок кода) там где тебе надо. Это должно подтолкнуть тебя давать функциям точные и понятные имена.
Важно запомнить, что колбэки - просто функции, но которые выполнятся не сразу, по мере чтения кода, а тогда когда произойдет определенное событие. Ключ к пониманию механизма коллбэков лежит в том, что ты никогда не узнаешь *когда* (в какой момент времени) закончится асинхронная операция (I/O), но ты будешь уверен в том, **где** (после какого события) операция закончится - на последней строке асинхронной функции (т.е. колбэка)! Порядок объявления колбэков не имеет никакого значения и не влияет на последовательность выполнения. Значение имеет только их логическая вложенность, иерархичность если хотите. Сперва ты разбиваешь свой код на функции (как обособленные части кода) и только потом используешь колбэки, чтобы описать зависмости между их вызовами.
Снова вернемся к программе. Метод `fs.readFile`, предлагаемый Нодой, выполняется асинхронно и требует много времени для своего выполнения. Рассмотрим происходящее детально: для выполнения функции требуется обратиться к ОСи, которой надо обратиться к ФС, которая живет на диске, который совершает тысячи оборотов в минуту. Диску надо задействовать магнитную головку (а это уже физический уровень, между прочим) чтобы прочитать данные и отправить их обратно по всем уровням нашей программе. Ты передаешь методу `readFile` функцию-колбэк, которая и будет вызвана после того как данные от ФС будут получены. Колбэк поместит полученные данные в переменную и только теперь вызовет твою функцию-коллбэк уже с имеющей значение переменной (не undefined). В этом случае переменная называется `fileContents`, т.к. в ней лежит содержимое всего файла.
Вспомните пример с заказом и очередью из 1 части. Во многих ресторанах вам ставят на стол номер, пока вы ждете свой заказ. Это очень похоже на коллбэк. Эти номера говорят официантам, что нужно сделать когда ваш заказ будет готов.
Вернемся к нашему примеру и вынесем выражение `console.log` в отдельную функциию и передадим её как коллбэк:
```js
var fs = require('fs')
var myNumber = undefined
function addOne(callback) {
fs.readFile('number.txt', function doneReading(err, fileContents) {
myNumber = parseInt(fileContents)
myNumber++
callback()
})
}
function logMyNumber() {
console.log(myNumber)
}
addOne(logMyNumber)
```
Теперь функцию `logMyNumber` можно передать как аргумент, который станет "колбэчной" переменной уже внутри функции `addOne`. После окончания выполнения `readFile` будет вызвана переменная `callback` (именно вызвана как функция: `callback()`). Вызываться могут только фукнции, так что если передать туда что-то другое, то это приведет к ошибке.
В JS когда функция вызывается внутри другой функции (как `callback()`), то она будет выполнена сразу. В таком контексте выражение `console.log` выполнится как `callback`-параметр, который на деле есть функция `logMyNumber`. Запонмите важную вещь, когда вы *определяете* (*define*) функцию, это ещё ничего не говорит о том, когда она будет вызвана. Чтобы она сработала надо явно произвести её вызов (*invoke*).
Чтобы окончательно закончить разбор нашего пример, выпишем все программные действия в той последовательности, в которой они выполнятся при запуске программы:
- 1: Код "пропарсится" (The code is parsed), т.е. если в нем есть синтаксические ошибки, программа не запустится. В процессе "парсинга" будут определены переменные `fs` и `myNumber` и функции `addOne` и `logMyNumber`. Заметьте, что на этом этапе идут только определения. Ни одна функция пока не вызвана.
- 2: Когда выполнится последняя строка программы, будет вызвана функция `addOne` с функцией `logMyNumber` в качестве аргумента-колбэка. Вызове `addOne` приведет к запуску асинхронную функцию `fs.readFile`. Этой части программы нужно время, чтобы завершиться.
- 3: Сейчас Нода будет бездействовать и ждать пока выполнится функция `readFile`. Если бы у неё были ещё какие-то задачи - она занялась бы ими.
- 4: Как только `readFile` заканчивает работу, в дело вступает колбэк-функция `doneReading`, которая парсит `fileContents` в поиске целого числа. Результат `parseInt` присваивается `myNumber`-у, потом увеличивает его (`myNumber`) значение на 1 и затем сразу вызывается функция `addOne`, переданная как параметр `callback` в `logMyNumber`.
Пожалуй, самая непривычная часть программирования с колбэками - то как функции подобно объектам могут храниться в переменных и передаваться под разными именами. Давать простые и образные имена своим переменным - очень важное умение для программиста, особенно когда он пишет код, который будут читать другие люди. Читая Нода-программы, если ты видишь переменную с именем `callback` или `cb` - скорее всего здесь ожидается функция-колбэк.
Ты наверняка слышал такие понятия как событийно-ориентированное программирование ('evented programming') или "ивент луп" ('event loop') (умышленно не переводил чтобы не запутывать читателя абстрактными выражениями. если встретите где-нибудь понятие "событийный цикл" - знайте, это одно и то же. - прим. перев.). Они обозначают тот самый способ, которым реализован `readFile`. Сначала Нода отправляет на выполнение метод `readFile`, потом ждет, пока тот отправит ей "ивент" о своем окончании. В процессе ожидания Нода может проверять, есть ли ещё невыполненые операции. Внутри Ноды есть список запущенных, но ещё не законченных операций; Нода устроена так, что обходит этот список снова и снова пока какая-нибудь операция не завершится. По завершении, она считается обработанной (get 'processed') и все колбэки, которые были завязаны на её окончание будут вызваны.
Иллюстрация сказанного через псевдокод:
```js
function addOne(thenRunThisFunction) {
waitAMinuteAsync(function waitedAMinute() {
thenRunThisFunction()
})
}
addOne(function thisGetsRunAfterAddOneFinishes() {})
```
Представьте, что у вас есть 3 асинхронные функции `a`, `b` и `c`. Каждой из них на выполнение надо 1 минуту, после чего она передает управление своему колбэку (её первый аргумент). Если тебе понадобится вызвать их последовательно сначала `a`, потом `b`, потом `c`, можно написать так:
```js
a(function() {
b(function() {
c()
})
})
```
Когда код начнет выполняться, `a` стартует сразу, затем через минуту она закончит выполнение и вызовется `b`, затем, ещё через минуту она закончит и вызовется `c` и наконец спустя 3 минуты, Нода остановится, потому что выполнять будет нечего. Есть и другие более выразительные способы чтобы описать приведенный пример, но суть в том, что если у тебя есть код который должен выполниться по окончании другого асинхронного кода, то тебе надо показать эту зависимость, поместив свой код в фукнцию и потом передать её как колбэк.
Такой способ построения программ требует не-линейного мышления. Рассмотрим список операций:
```
прочитать файл
обработать этот файл
```
Если перевести их в псевдокод, то мы получим:
```
var file = readFile()
processFile(file)
```
Такой тип линейного (последовательного, шаг-за-шагом) построения программ не работает в Ноде. Если код начнет выполняться в таком виде, то `readFile` и `processFile` будут выполняться одновременно. Так мы не сделаем зависимость на окончание выполнения `readFile`. Вместо этого, тебе надо указать что `processFile` должен дождаться окончания работы `readFile`. И это как раз то, для чего и нужны колбэки! А благодаря возможностям JS ты можешь описывать такие зависимости разными способами:
```js
var fs = require('fs')
fs.readFile('movie.mp4', finishedReading)
function finishedReading(error, movieData) {
if (error) return console.error(error)
// do something with the movieData
}
```
Но ты можешь написать код по-другому и он тоже сработает:
```js
var fs = require('fs')
function finishedReading(error, movieData) {
if (error) return console.error(error)
// do something with the movieData
}
fs.readFile('movie.mp4', finishedReading)
```
Или даже так:
```js
var fs = require('fs')
fs.readFile('movie.mp4', function finishedReading(error, movieData) {
if (error) return console.error(error)
// do something with the movieData
})
```
## События*
*События (Events) они же 'ивенты' - суть одно и то же, просто термины употребляются разными людьми в разных контекстах по-своему. Поэтому призываю не привязываться к словам, а зреть в корень. - прим. перев.
В Ноде, если тебе нужен модуль [events](https://nodejs.org/api/events.html) ты можешь использовать т.н. "генератор событий" ('event emitter'), который сам используется Нодой для своих API, которые что-то генерируют.
События - основной паттерн в программировании, более известный как "Наблюдатель" ['observer pattern'](https://en.wikipedia.org/wiki/Observer_pattern) или издатель\подписчик (publish/subscribe или совсем кратко 'pub/sub') . Поскольку колбэки реализуют модель отношений один-к-одному (one-to-one) между колбэком и тем кто его вызывает, события реализуют тот же паттерн для другого типа отношений - многие-ко-многим (many-to-many).
Принципы работы событий проще понять как некую подписку, они позволяют тебе "подписаться" на что-то, на совершение какого-то действия и твое гарантированное уведомление о нем. Ты можешь сказать "когда произойдет X сделать Y", в то время как простые колбэки (plain callbacks) понимали только "сделай X потом сделай Y". Т.о., подход событий более универсальный чем подход колбэков.
Несколько примеров использования (use cases) где события смогли бы заменить колбэки:
- Чат-комната (Chat room) где ты бы смог оповещать разных слушателей (listeners) о своих сообщениях
- Игровой сервер, которому нужно знать когда игроки подключились, отключились, переместились, ударили, прыгнули и т.п. (совершили игровые действия)
- Игровой движок где ты можешь позволить разработчикам подписываться на события примерно так: `.on('jump', function() {})`
- Низкоуровневый веб-сервер, для которого нужен открытый API, чтобы перехватывать события, например так `.on('incomingRequest')` или так `.on('serverError')`
Если попробовать написать модуль, который подключается к чат-серверу используя только колбэки, то это будет выглядеть примерно так:
```js
var chatClient = require('my-chat-client')
function onConnect() {
// have the UI show we are connected
}
function onConnectionError(error) {
// show error to the user
}
function onDisconnect() {
// tell user that they have been disconnected
}
function onMessage(message) {
// show the chat room message in the UI
}
chatClient.connect(
'http://mychatserver.com',
onConnect,
onConnectionError,
onDisconnect,
onMessage
)
```
Выглядит довольно неуклюже, поскольку все функции для вызова `.connect` надо передавать в одном месте и в определенном порядке. Напишем то же самое, но с помощью событий:
```js
var chatClient = require('my-chat-client').connect()
chatClient.on('connect', function() {
// have the UI show we are connected
})
chatClient.on('connectionError', function() {
// show error to the user
})
chatClient.on('disconnect', function() {
// tell user that they have been disconnected
})
chatClient.on('message', function() {
// show the chat room message in the UI
})
```
Похоже на вариант с чистыми колбэками (pure-callbacks), но вводит новый метод `.on`, к-ый и *подписывает* функцию-колбэк на определенный тип событий. Это значит, что ты можешь выбирать на какие события ты хочешь подписаться из `chatClient`. Ты даже можешь подписать на одно событие несколько разных колбэков:
```js
var chatClient = require('my-chat-client').connect()
chatClient.on('message', logMessage)
chatClient.on('message', storeMessage)
function logMessage(message) {
console.log(message)
}
function storeMessage(message) {
myDatabase.save(message)
}
```
## Потоки
На ранних стадиях развития Ноды API для работы с ФС и сетью пользовались своими собственными приемами в работе с потоками ввода/вывода (streaming I/O). Например, для файлов в файловых системах применялись так называемые «файловые дескрипторы», соответственно, модуль fs был наделён дополнительной логикой, позволяющей их отслеживать, в то время, как для сетевых модулей такая концепция не использовалась. Несмотря на незначительные отличия в семантиках подобно этим, на самом низком уровне, где надо было считывать и записывать данные обе кодовые базы во многом повтряли друг друга.
Команда, работающая над Нодой, осознала, что такое положение дел будет только путать разработчиков, которым придется изучать две группы семантик, чтобы сделать по сути одно и тоже. Они сделали новый API, который назвали `Потоком` (`Stream`) и переписали весь код для работы с ФС и сетью уже на нем. Главная задача Ноды - сделать работу с ФС и с сетями простой и удобной, поэтому было разумно иметь единый общий подход, который использовался бы повсюду. Главный плюс заключается в том, что большинство паттернов подобных этим на данный момент уже реализованы и маловероятно, что Нода в будущем сиьно изменится.
Есть 2 отличных ресурса, которые можно использовать для изучения потоков в Ноде. Первый - stream-adventure (см. раздел "Изучи Ноду интерактивно") и другой - справочник, называемый Stream Handbook.
### Stream Handbook
[stream-handbook](https://github.com/substack/stream-handbook#introduction) - гайд, похожий на этот, в котором есть ссылки на всё, что только может понадобиться при изучении потоков.
[](https://github.com/substack/stream-handbook)
## Модули и npm. Экосистема Ноды
Ядро Ноды (Node core) включает в себя более 20 модулей, которые делятся на низкоуровневые, такие как `events` и `stream` и высокоуровневые типа `http` and `crypto`.
Такая структура выбрана неслучайно. Ядро изначально предполагалось сделать небольшим и независмым от платформы, а главная задача модулей - обеспечивать работу с основными I/O протоколами и форматами.
Для всего остального есть пакетный менеджер Node [npm](https://www.npmjs.com/). Каждый может создать модуль и опубликовать его для npm. На момент написания этих строк на npm было около 34k модулей.
### Как найти нужный модуль
Представьте, вам надо сконвертить PDF файлы в текстовые. Начать стоит с команды `npm search pdf`:

Он выдаст кучу результатов. npm, действительно, очень популярен и вы наверняка сможете найти здесь подходящее решение для своей задачи. Если внимательно рассматривать каждый модуль и фильтровать результаты поисков (убирая, например, модули PDF-генераторов) то в конце концов увидишь список:
- [hummus](https://github.com/galkahana/HummusJS/wiki/Features) - c++ pdf manipulator
- [mimeograph](https://github.com/steelThread/mimeograph) - api on a conglomeration of tools (poppler, tesseract, imagemagick etc)
- [pdftotextjs](https://www.npmjs.com/package/pdftotextjs) - wrapper around [pdftotext](https://en.wikipedia.org/wiki/Pdftotext)
- [pdf-text-extract](https://www.npmjs.com/package/pdf-text-extract) - another wrapper around pdftotext
- [pdf-extract](https://www.npmjs.com/package/pdf-extract) - wrapper around pdftotext, pdftk, tesseract, ghostscript
- [pdfutils](https://www.npmjs.com/package/pdfutils) - poppler wrapper
- [scissors](https://www.npmjs.com/package/scissors) - pdftk, ghostscript wrapper w/ high level api
- [textract](https://www.npmjs.com/package/textract) - pdftotext wrapper
- [pdfiijs](https://github.com/fagbokforlaget/pdfiijs) - pdf to inverted index using textiijs and poppler
- [pdf2json](https://github.com/modesty/pdf2json/blob/master/readme.md) - pure js pdf to json
Есть много модулей, которые повторяют функционал друг друга, но предоставляют разные API и многие требует установки внешних зависимостей (как например, `apt-get install poppler`).
Несколько примеров, на что стоит обращать внимание при выборе нужного модуля:
- `pdf2json` единственный модуль, написанный на чистом js, что означает его легкость в установке, особенно на маломощных устройствах типа raspberry pi или на Windows, у которого нативный код не может быть перенесен на другую платформу
- модули типа `mimeograph`, `hummus` и `pdf-extract` объединяют в себе несколько низкоуровневых модулей чтобы предоставить к ним высокоуровневый API
- много модулей используют под собой никсовские тулзы `pdftotext`/`poppler`
Давайте сравним `pdftotextjs` и `pdf-text-extract`, оба являются лишь оболочками вокруг утилиты `pdftotext`.

Сходства:
Оба модуля:
- обновлены относительно недавно
- имеют свои репозитории на гитхабе (что очень важно)
- имеют README файлы
- каждую неделю скачиваются пользователями
- имеют открытую лицензией (т.е. может воспользоваться любой)
По данным `package.json` и одной статистике модуля сделать правильный выбор совсем непросто. Давайте сравним файлы описаний README:

Оба имеют простые понятные описания, значки CI, инструкции по установке, примеры использования, инструкции по запуску тестов. Отлично! Но какой же выбрать? Сравним код внутри:

В `pdftotextjs` примерно 110 строк кода, а в `pdf-text-extract` около 40, но у обоих всё сводится по сути к одной строке:
```
var child = shell.exec('pdftotext ' + self.options.additional.join(' '));
```
Делает ли это одну лучше другой? Трудно сказать! Здесь важно самому прочитать код и сделать свои выводы. Если найдешь модуль, который тебе понравится, набери `npm star modulename`. Так можно сказать npm, что тебе понравилось пользоваться этим модулем.
### Модульный подход к разработке
npm отличается от большинства пакетных менеджеров тем, что устанавливает модули в папку внутри других существующих модулей. Это может быть непонятно сразу, но это чуть ли не ключевой фактор успеха npm.
Многие пакетные менеджеры (далее ПМ) устанавливают их глобально (т.е. к пакету можно обратиться прямо из консоли из любой директории). Например, Если набрать `apt-get install couchdb` на Debian Linux - он поставит последнюю стабильную версию (latest stable version) CouchDB. Теперь, если ты установишь CouchDB как зависмость от другого пакета или программы и эта программа требует более старой версии CouchDB, то тебе придется удалить свежую версию CouchDB и только после этого поставить более старую. У тебя не получится поставить две версии CouchDB потому что Debian устанавливает все пакеты в одно место.
Это относится не только к Debian. Многие ПМы языков программирования работают по тому же принципу. Чтобы избежать описанного выше конфликта зависимостей, было разработано виртуальное окружение (далее ВО) (virtual environment), похожее на [virtualenv](http://python-guide.readthedocs.org/en/latest/dev/virtualenvs/) у Python или [bundler](http://bundler.io/) из мира Ruby. Они разбивают твое привычное окружение на много виртуальных, по одному на каждый проект, но внутри каждое такое окружение ставит пакеты всё так же глобально для этого виртуального. Такие ВО не всегда решают проблему, иногда они только раздувают её, создавая новые уровни сложности.
Для npm установка глобальных модулей - антипаттерн (плохой подход) (anti-pattern).
Также как в программах на JS ты не станешь использовать глобальные переменные, ты также не станешь устанавливать модули глобально (пока тебе не понадобится модуль с исполняемым файлом чтобы обратиться к нему твоем глобальном `PATH`, но тебе редко такое может понадобиться -- об этом позже).
#### Как работает команда `require`
When you call `require('some_module')` in node here is what happens:
1. Если вызываемый файл `some_module.js` существует в текущей папке, то Нода подгрузит его, иначе
2. Нода поищет в текущей папке папку с именем `node_modules` и внутри неё папку с именем `some_module`
3. Если она и её не найдет, то он поднимется на 1 уровень вверх и повторит шаг 2
Этот цикл повторится пока Нода не доберется до корневой папки ФС, оттуда он проверит все папки глобальных модулей (такие как `/usr/local/node_modules` on Mac OS) и если так и не встретит `some_module`, только тогда Нода выбросит "эксепшн" (исключение) (throw an exception).
Рассмотрим пример такого поиска:

Находясь в папке `subsubfolder` и вызвав `require('foo')`, Нода будет искать папку `subsubfolder/node_modules`. Здесь он его не найдет -- папка здесь нарочно называется `my_modules`. Тогда Нода поднимется вверх на 1 уровень и попробует искать снова, - на картинке это выглядело бы как `subfolder_B/node_modules`, которой также не существует. Третья попытка окажется удачной - папка `folder/node_modules` существует *и* имеет внутри себя папку `foo`. Если бы `foo` и здесь не было - Нода продолжила бы поиск в родительской директории.
Отметим, что если бы Нода была вызвана из `subfolder_B`, то она бы никогда не попала в папку `subfolder_A/node_modules`. Поднимаясь вверх по дереву папок она сможет попасть только в `folder/node_modules` .
Одно из преимуществ подхода npm в том, что модули сами могут устанавливать свои зависимости, причем тех версий, которые актуальны для них самих. В нашем примере, модуль `foo` оказался крайне популярен - 3 копии пакета, по одному на каждую родительскую папку самогО модуля. Причиной этому можеть быть то, что каждый родительский модуль нуждается в своей версии пакета `foo`, т.е. `folder`у нужен `foo@0.0.1`, `subfolder_A`у нужен `foo@0.2.1` и т.д.
Посмотрим, что произойдет когда мы исправим ошибку имени директории, сменив его с `my_modules` на правильное `node_modules`:

Чтобы протестить какой модуль фактически загружен Нодой, вы можете вызвать команду `require.resolve('some_module')`, которая выведет путь к тому модулю, который Нода нашла при обходе директорий. `require.resolve` может оказаться полезной когда вам надо убедиться в том, что загружен именно тот модуль и той версии которую вы ожидаете -- бывает что версия подключенного модуля отличается от той, которую мы ожидаем увидеть - это значит, Нода нашла такой модуль быстрее, чем тот, который нам нужен.
### Как написать свой модуль
Теперь, когда мы узнали как искать модули и как подключать их в программу вы можете начать писать свои.
#### Самый простой из возможных модулей
Модули Ноды крайне легковесны (lightweight). Один из самых простых модулей выглядит так:
`package.json`:
```js
{
"name": "number-one",
"version": "1.0.0"
}
```
`index.js`:
```js
module.exports = 1
```
По умолчанию (By default), когда ты вызываешь `require('module')`, то Нода пробует загрузить `module/index.js`. С любым другим именем файла это не сработает, пока вы не укажете его явно в файле `package.json` в поле `main`.
Положите оба этих файла в папку `number-one` (значение `name` в `package.json` должно совпадать с именем папки) и вы получите готовый рабочий модуль.
Вызывая функцию `require('number-one')` вы получите то значение, которое установлено для `module.exports` внутри модуля.

Для создания модуля есть ещё способ, даже более быстрый. Выполните эти команды:
```sh
mkdir my_module
cd my_module
git init
git remote add git@github.com:yourusername/my_module.git
npm init
```
Выполнив в консоли `npm init` создастся валидный (valid) `package.json` и если запустить его в существующем `git` репозитории, то он автоматом проставит поле `repositories` внутри `package.json`.
#### Добавляем зависимости
У модуля может быть список других модулей из npm или GitHub в поле `dependencies` в файле `package.json`. Чтобы установить модуль `request` как новую зависимость и сразу доавбить его в `package.json` выполните следующую команду в корневой папке модуля:
```sh
npm install --save request
```
Этим вы устанавливаете копию `request` в закрытую извне папку `node_modules`, и наш `package.json` будет похож на этот:
```
{
"id": "number-one",
"version": "1.0.0",
"dependencies": {
"request": "~2.22.0"
}
}
```
По умолчанию, `npm install` подтягивает последнюю опубликованную версию модуля.
## Разработка клиентской части с npm
Основное заблуждение о npm - то что если в названии встречается слово 'Node.js', то это будет использоваться только на сервере. Совсем нет. npm - менеджер пакетов Ноды, он отвечает за те модули, которые Нода упаковывает. Сами же модули могут быть чем угодно -- это просто папка с файлами, собранная в архив и файлом `package.json`, который описывает версию модуля и список своих зависимостей (вместе с версиями тех модулей, от которых он сам зависит, так что рабочие версии всех модулей поставятся автоматически). Эта цепочка очень длинная - модуль зависят от других модлуей, к-ые в свою очередь зависят от других и т.д.
Утилита [browserify](http://browserify.org/), написанная на Ноде, создана чтобы сконвертить любой Нодовский модуль так, чтобы его код можно было выполнять в браузере. Не со всеми модулями такое получится сделать (браузер, например, не может выступать в качестве HTTP сервера), но со многими модулями такое проходит.
Чтобы попробовать возмоности Npm в браузере используйте модуль [RequireBin](http://requirebin.com/), это приложение, которое я сделал, вобрало в себя плюсы [Browserify-CDN](https://github.com/jfhbrook/wzrd.in), который сам внутри использует browserify, но результат выдает через HTTP (а не на консоль, как это делает browserify).
Скопируем этот код в окно RequireBin нажмем "Run Code":
```js
var reverse = require('ascii-art-reverse')
// makes a visible HTML console
require('console-log').show(true)
var coolbear =
" ('-^-/') \n" +
" `o__o' ] \n" +
" (_Y_) _/ \n" +
" _..`--'-.`, \n" +
" (__)_,--(__) \n" +
" 7: ; 1 \n" +
" _/,`-.-' : \n" +
" (_,)-~~(_,) \n"
setInterval(function() { console.log(coolbear) }, 1000)
setTimeout(function() {
setInterval(function() { console.log(reverse(coolbear)) }, 1000)
}, 500)
```
[Или другой пример](http://requirebin.com/?gist=679b58d4237eaca37173) (смело меняйте код, чтобы увидеть что будет):
[](http://requirebin.com/embed?gist=679b58d4237eaca37173)
## Правильный выбор инструмента
Как любой хороший инструмент, Нода как никто лучше справляется с тем кругом задач, для решения которых она была сделана. К примеру, фреймворк Rails отлично подходит для построения сложной бизнес-логики [business logic](https://en.wikipedia.org/wiki/Business_logic), где код используется для представления реальных бизнес-объектов. И хотя чисто технически такая задача Ноде под силу, но решая её вы у вас возникнут проблемы, потому что Нода создавалась для решения задач ввода/вывода, а не для написания 'бизнес-логики'. Каждый инструмент создается под свои задачи. Надеюсь, этот гайд (guide) поможет вам понять и прочувствовать сильные стороны Ноды, чтобы у вас выработалось понимание того, в каких случаях она будет вам полезна.
### Чем не является Нода?
Приципиально, Нода - лишь инструмент для управления потоками ввода/вывода в ФС и сетях, сама Нода не затрагивает возможности других частей системы, это делают уже сторонние модули. Здесь описаны несколько вещей которые ошибочно приписывают Ноде:
#### Веб-фреймворки
Существуют фреймворки, построенные на Ноде (фреймворк здесь понимается как пакет для решения какой-то высоскоуровневой задачи, например моделирование бизнес-логики), но сама Нода не веб-фреймворк.
Веб-фреймворки, написанные на Ноде не всегда соблюдают те принципы и правила, которые закладывались в архитектуру Ноды.
#### Синтаксис языка
Нода использует JS и не собирается что-то менять. У Felix Geisendörfer есть отличное описание своего видения стиля Ноды [here](https://github.com/felixge/node-style-guide).
#### Языковые абстракции
Всегда когда это возможно, Нода будет использовать самый простой способ для выполнения задачи, перед которой её поставили. Пограммирование вещь непростая, особенно в JS, где на каждую проблему найдется 1000 возможных решений! Эта та причина, по которой Нода старается всегда находить самое простое и универсальное решение. Но если ты сталкиваешься с задачей которая приводит к запутанному решению и тебе не нравятся те скорые решения, которые предлагает Нода, ты в праве самостоятельно решить её в своем приложении - выбрать модуль, который тебе понравится, или абстракции которые тебе подойдут.
Хорошей иллюстрацией этих слов служит использование колбэков. В ранних версиях Ноды был популярен прием с использованием промисов ('promises'), которые позволяли писать асинхронный код так, чтобы выглядел он как линейный. Но эту фичу исключили из ядра Ноды по нескольки причинам:
- они гораздо сложнее в использовании чем колбэки
- их можно использовать, установив специальный модуль
Рассмотрим пример с чтением файла. Когда ты читаешь файл, тебе надо знать, какие ошибки произошли, например, отказал жесткий диск прямо во время чтения файла. Если бы Нода использовала промисы, то приходилось бы "ветвить" свой код почти как здесь:
```js
fs.readFile('movie.mp4')
.then(function(data) {
// do stuff with data
})
.error(function(error) {
// handle error
})
```
Это добавляет ненужную сложность, что понравится не каждому. Вместо двух отдельных функций в Ноде используется единая колбэк-функция. Для неё действуют правила:
- Когда ошибки нет, первым аргументом идет null
- Когда ошибка есть, передавать её первым аргументом
- Остальные аргументы могут использованы как угодно (обычно, это будут данные или ответы на запросы, ведь Нода по большей части работает с вводом/выводом)
Отсюда и такой стиль написания колбэков:
```js
fs.readFile('movie.mp4', function(err, data) {
// handle error, do stuff with data
})
```
#### Threads/fibers/non-event-based concurrency solutions
Замечание: Если вы ещё не сталкивались с этими терминами, возможно, вам будет проще освоить Ноду, ведь забыть что-то так же сложно как и запомнить.
Чтобы делать всё быстро Нода использует внутри себя потоки (threads), но сама скрывает их от пользователя. Если вы технарь, и вам интересно как устроена Нода внутри, вам совершенно точно надо прочитать об [архитектуре библиотеки libuv](http://nikhilm.github.io/uvbook/), C++ I/O слое, на котором держится сама Нода.
## Лицензия

Creative Commons Attribution License (do whatever, just attribute me)
http://creativecommons.org/licenses/by/2.0/
Donate icon is from the [Noun Project](https://thenounproject.com/term/donate/285/)
================================================
FILE: readme.zh-cn.md
================================================
# Node的艺术
## Node.js入门
本文档假定读者已经懂了以下的两样东西:
- 懂得至少一种编程语言。例如:JavaScript,Ruby,Python,Perl或其他编程语言。如果你还不是程序员,你不懂编程语言,你可以阅读[JavaScript for Cats](http://jsforcats.com/)。:cat2:
- git和github。这是一个开源的协作工具,Node社区的用户使用git共享模块。你需要懂得基本操作就能了。这里有三篇很好的入门教程:[1](https://github.com/jlord/git-it-electron#readme), [2](http://zachbruggeman.me/github-for-cats/), [3](http://opensourcerer.diy.org/)
This short book is a work in progress + I don't have a job right now (if I did I wouldn't have the time to write this). If you like it then please consider donating via [gittip](https://www.gittip.com/maxogden/) so that I can write more!
> 译者: 上面这段我没有翻译,因为我希望保持原文。上面作者提到,目前他还没找到工作。如果你喜欢这个文档,希望你可以通过[gittip](https://www.gittip.com/maxogden/)乐捐给作者。这样作者才能够写更多。
[](https://www.gittip.com/maxogden/)
## 目录
- [了解Node](#了解Node)
- [核心模块](#核心模块)
- [回调函数](#回调函数)
- [事件](#事件)
- [流](#流)
- [模块](#模块)
- [用npm在客户端开发](#用npm在客户端开发)
- [析薪杝矣](#析薪杝矣)
## 了解Node
Node.js是一个开源项目,目的是让你通过编写JavaScript的程序进行网络、文件系统或其他I/O源的沟通。就这些!它只是一个简单而稳定的I/O平台,你可以在这个平台上架构模块。
有没有I/O出的例子? 我这里有一张图,上面是我用Node.js制作的程序,你可以看到上面有很多I/O源:

如果你无法明白上图显示的所有东西,这是没问题的。重点是你看到一个Node的运作(在中间六边形那个),它就像经纪人,管理全部I/O的端口(橙色和紫色的线条代表I/O)。
一般上我们编写的程序可以分为以下两类:
- 很难编写,但是效率超高(就像用C从零开始编写一个Web服务器)
- 很简单编写,但是不够效率/强大(就像有人上传5GB的文件去你服务器,但是服务器宕机了)
Node试图做到平衡在这两者之间:在大多数用列做到高效运行,而且容易明白和开发。
Node不是以下两样东西:
- 不是Web框架 (不像Rails或Django,尽管它可以被用来做这样的事情)
- 不是编程语言(Node是使用JavaScript编程,它没有自己的编程语言)
相反,Node是:
- 设计上简单,而且容易明白和使用的平台
- 适合那些需要快速和处理很多I/O链接的程序
在基层,Node可以作为一种工具,并编写出以下两类程序:
- 需要使用到Web协议(如:HTTP、TCP、UDP、DNS和SSL)的网络程序
- 需要对文件系统或者本地进程/内存进行读入和读出操作的程序
什么是“I/O程序”? 这里有一些常见的I/O源:
- 资料库 (如:MySQL、PostgreSQL、MongoDB、Redis、CouchDB)
- APIs(如:Twitter、Facebook、Apple Push Notifications)
- HTTP/WebSocket的链接(从用户的Web应用程序)
- 文件档(图像尺寸伸缩软件、视频编辑软件、网络收音机)
Node能够[异步处理](http://en.wikipedia.org/wiki/Asynchronous_I/O)多个不同种类的I/O源。比如说,假设你来到快餐店,你向店员要了一个芝士汉堡,他们会马上为你下单和准备汉堡。然后,他们会要求你在旁边等汉堡完成。在你等待这段时间,他们可以接受其他订单和帮其他人准备汉堡。试想下,如果你站在柜台前面,一直等到你的芝士汉堡完成,那么你就阻碍了后面的人下订单,厨师也不能帮其他人准备汉堡!我们称这个为**阻塞I/O**,因为一次只能处理一个I/O操作(厨师一次只能准备一个汉堡)。Node,不是这样的,它是**非阻塞**性质,就是说它能一次准备很多汉堡。
多谢Node非阻塞的性质,让我们可以实现以下这么有趣事情:
- 控制[Quadcopters飞行](http://nodecopter.com)
- 编写IRC谈天机器人
- 制作一个[双脚走路的机器人](http://www.youtube.com/watch?v=jf-cEB3U2UQ)
## 核心模块
首先,你需要在电脑上安装Node。Node安装很简单,只需浏览[nodejs.org](http://nodejs.org)和点击`Install`.
Node拥有一组核心模块(通常被称为`Node核心`)提供公共 API 让你编程时候调用。我们可以调用`fs`模块来操作文件系统。当我们要进行网络操作时候,我们会调用网络模块,例如:`net`(TCP),`http`,`dgram`(UDP)。
除了`fs`和网络模块之外,Node核心还有很多其他的核心模块。如`dns`模块用来异步解析DNS查询。`os`模块可以用来收集操作系统的资讯,如tempdir的路径。`buffer`模块可以处理二进制数据。还有些模块可以处理URL和路径,如:`url`,`querystring`和`path`等等。大部分的核心模块都支持Node的主要使用目标:快速编写能够进行文件或网络操作的程序。
Node通过回调,事件,数据流和模块来控制I/O。如果你学会了这四样东西如何工作,那么你就能够灵活使用任何核心模块,而且你还会懂得模块的基本接口。
## 回调函数
如果想真的弄明白怎么使用Node,回调函数是你需要了解的东西中最重要的,没有之一。回调函数倒不是有了Node后才有的,只不过这功能是JavaScript中尤其好用的一个。
回调函数是指非同步执行的,或者是在将来某个时间才会被执行的函数。同步代码运行的顺序是从上至下,而非同步的程序却是在不同的时间运行不同的函数,这些事件都基于某些某同步函数的顺序和运行速度,包括HTTP请求和从文件系统里读取内容等等。
这种同步和非同步之间的差异可能会让人比较困惑,因为看一个函数是不是非同步,很大程度上取决于具体的情况。下面是一个很简单的同步函数的例子:
```js
var myNumber = 1
function addOne() { myNumber++ } // 定义函数
addOne() // run the function
console.log(myNumber) // 结果显示2
```
上面的代码定义了一个函数,然后调用了它,之间没有任何停留。当该函数被调用时,它立即把那个数字加上1,所以我们可以预见到,调用过该函数后,那个数字的值会变成2。
现在假设我们把数字存在一个叫`number.text`的文件里:
```js
var fs = require('fs') // require是Node提供的一个特别函数
var myNumber = undefined // 数字被存在文件里,因此我们并不知道它的值
function addOne() {
fs.readFile('./number.txt', function doneReading(err, fileContents) {
myNumber = parseInt(fileContents)
myNumber++
})
}
addOne()
console.log(myNumber) // 结果显示undefined
```
为什么这些显示出来的值是`undefined`?因为在上面的代码中,我们用了`fs.readFile`这个方法,而它恰好是个非同步方法。一般来说,需要和硬盘沟通或是从通信网络获得数据的,都是非同步的。只是需要从内存里或CPU里读些东西的话,就是同步的。这是因为I/O(输入输出)是非常非常非常慢的。如果要大概形容一下,从硬盘里读取大概比从内存里读取慢了10万倍。
当这个程序运行的时候,所有的函数都马上被定义,但它们不是马上都被执行的。这是非同步编程的一个基础概念。当`addOne`被调用的时候,Node执行`readFile`这个方法,但不等到`readFile`结束,它就继续进行下一个不需要等待就能执行的函数了。如果没有可以执行的东西了,Node要么会停下来,等待文件读取或是网络通讯结束,要么就结束运行,返回到命令行。
当`readFile`终于把文件读完的时候(需要的时间从几毫秒到几秒到几分钟不等,要看硬盘有多快),Node会执行`doneReading`这个函数,并把报的错(如果读文件的时候有报错的话)和文件的内容传给它。
在上面的程序中,之所以会显示`undefined`,是因为我们的代码并没有在任何地方注明了要在文件读取完成后再`console.log`出数字。
如果你有一些想要反复执行的代码,你应该做的第一件事就是把这些代码放在一个函数里。然后,在你需要执行那些代码的时候,调用这个函数就好了。你给函数起的名字最好能让人一看就知道这个函数是做什么的。
回调函数,不过是在将来某个时间被执行的函数。要理解回调函数,很关键的一点是它被使用的时机。你使用回调函数的前提是,你不知道**什么时候**某个非同步进程会结束,但知道这个进程会在**哪里**结束————就在那个非同步函数的最后一行!你在什么地方声明这些函数并不重要,重要的是这些函数之间的逻辑顺序。把代码分装进各个函数之后,如果一个函数的执行取决于另一个函数何时结束,就该使用回调函数了。
上面代码中的`fs.readFile`方法是Node自带的,这个方法是非同步的,而且要花费很长时间。想想看它要做多少事情:它要进入操作系统,进入文件系统,文件系统可是在硬盘上的,硬盘可能转得飞快,也可能根本就不转。然后它要用激光读出数据,并把数据传回你的JavaScript程序。当你给了它一个回调函数后,它就可以在成功从文件系统中取得数据以后,调用那个回调函数。它会把数据放在一个变量里,交给你给的回调函数,我们给这个变量起的名字叫做`fileContents`,因为变量中包含的是读取到的文件内容。
想想看这个教程刚开始时的那个餐厅的例子。在很多餐厅,在你点的菜上来之前,服务生会放一个数字牌在你桌上。这个和回调函数很类似。回调函数的作用就是告诉服务器在你的芝士汉堡好了后要做些什么。
现在,让我们把`console.log`放进一个函数里作回调函数使用吧。
```js
var fs = require('fs')
var myNumber = undefined
function addOne(callback) {
fs.readFile('./number.txt', function doneReading(err, fileContents) {
myNumber = parseInt(fileContents)
myNumber++
callback()
}
}
function logMyNumber() {
console.log(myNumber)
}
addOne(logMyNumber)
```
现在`logMyNumber`这个函数可以被传给`addOne`作为回调函数了。在`readFile`完成后,`callback`这个变量会被执行(也就是`callback()`)。只有函数才能被执行,所以如果你提供一个不是函数的东西,程序会出错。
在JavaScript里,当函数被调用,其包含的代码会立刻被执行。在这个例子里,`console.log`会被执行,因为`callback`其实就是`logMyNumber`。要记得,你*定义*了一个函数,不代表它会执行!你一定得*调用*它才行。
如果要更细地分析一下这个例子,下面是按时间顺序排列的所有发生的事件:
- 1: 代码被分析,这时,如果有任何语法错误,程序会停止并报错。
- 2: `addOne`被调用,以`logMyName`作为它的回调函数,也就是我们想在`addOne`结束后执行的函数。接下来,非同步的`fs.readFile`马上开始运行。这个部分要花上点时间。
- 3: Node暂时没事做的,于是它就闲下来等待着`readFile`结束。
- 4: `readFile`结束了,`doneReading`这个函数被调用,它把数字加上1然后马上调用回调函数————也就是我们传给`addOne`的`logMyNumber`。
也许关于回调函数最难理解的部分是,为什么函数可以被存在变量里被传来传去,而且还有着变来变去的名字。要让你的代码更容易被看懂,给你的函数起简单明了的名字是很重要的一部分。总的来说,在使用Node时,如果你看见一个变量叫做`callback`或是它的缩写`cb`,你差不多可以确定它就是一个函数。
你可能听过一个术语叫“事件驱动式编程”,或者叫“事件循环”。`readFile`这类的函数就利用了“事件循环”。Node首先开始运行`readFile`,并等待着`readFile`发回一个事件。在Node等待的这段时间,它可以继续运行其他的东西。在Node里有一个列表,里面记下了所有开始运行却还没有发回结束信号的事,Node就一遍遍循环检查这个列表,看看有没有事情完成了。它们运行完之后,就会被Node处理掉,也就是说,需要运行的回调函数会被运行。
下面是上面例子的伪代码写法:
```js
function addOne(thenRunThisFunction) {
waitAMinuteAsync(function waitedAMinute() {
thenRunThisFunction()
})
}
addOne(function thisGetsRunAfterAddOneFinishes() {})
```
假设你有三个非同步函数:`a`、`b`,和`c`。它们要花上一分钟来运行,运行完了之后会调用一个回调函数(函数以第一个参数的形式被传进函数)。如果你想让Node先运行a,a运行完后运行b,b运行完后再运行c,那么程序是下面这样的:
```js
a(function() {
b(function() {
c()
})
})
```
当这段代码被运行时,`a`马上就会被运行,一分钟后`a`结束运行,`b`开始执行,再一分钟后,`b`结束运行,`c`开始运行。最后,也就是三分钟后,Node会停止运行,因为所有事都运行完了。上面的代码可能看起来没那么漂亮,但重点是,如果有些代码需要在某些非同步的事情运行完了之后再运行,你需要做的是把那些代码放进一个函数,当作回调函数传给非同步函数,以表示回调函数中的代码要依赖非同步的部分运行结束才能运行。
Node要求你用非线性的思维思考。看看下面这两件事:
```
read a file
process that file
```
如果你只是不假思索地把这两件事改成伪代码,你会这么写:
```
var file = readFile()
processFile(file)
```
这种线性的代码不是Node的风格。(线性是指一步接一步、按照顺序地)。如果上面的代码被运行了。那么`readFile`和`processFile`会同时被调用。这根本说不通,因为`reafFile`要花上一阵子时间才能运行结束。正确的做法是,表达清楚`processFile`是要依赖`readFile`结束才能运行的。这就是回调函数的作用了!因为JavaScript的特点,有好几种方法可以表达这种依赖性:
```js
var fs = require('fs')
fs.readFile('movie.mp4', finishedReading)
function finishedReading(error, movieData) {
if (error) return console.error(error)
// do something with the movieData
}
```
不过你这样写也可以,照样会成功运行:
```js
var fs = require('fs')
function finishedReading(error, movieData) {
if (error) return console.error(error)
// do something with the movieData
}
fs.readFile('movie.mp4', finishedReading)
```
甚至像下面这样:
```js
var fs = require('fs')
fs.readFile('movie.mp4', function finishedReading(error, movieData) {
if (error) return console.error(error)
// do something with the movieData
})
```
## 事件
在Node中如果你加载了[events](http://nodejs.org/api/events.html)模块, 就可以用被称作`event emitter`(事件分发器)的功能。 Node在它的API中使用这一功能分发事件。
在编程中运用`事件`是一种常见的方法。它还有一个我们更为熟知的名字[观察者模式](https://zh.wikipedia.org/wiki/%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F),或者`发布/监听`模式。在回调函数的模式中,调用回调函数的命令与等待回调函数的命令间的关系是一一对应的,而在事件模式中这两种命令的关系可以是多对多的。
理解事件最简单的方式,就是把它当成一个你监听的东西。如果说在回调函数里面我们的逻辑是`先做X,再做Y`,那么在事件中我们的逻辑是`当X发生时,做Y`。
以下是一些常见的用事件取代回调函数的例子:
- 需要向所有听众广播的聊天室
- 需要及时了解玩家上线、下线、运动、设计、跳跃等动作的游戏服务器
- 需要能让开发者执行`.on('jump', function() {})`这种命令的游戏引擎
- 能够执行`.on('incomingRequest')` 或 `.on('serverError')`这一API的低端web服务器。
如果我们想只用回调函数写一个连接聊天服务器的模块的话,代码会长这样:
```js
var chatClient = require('my-chat-client')
function onConnect() {
// have the UI show we are connected
}
function onConnectionError(error) {
// show error to the user
}
function onDisconnect() {
// tell user that they have been disconnected
}
function onMessage(message) {
// show the chat room message in the UI
}
chatClient.connect(
'http://mychatserver.com',
onConnect,
onConnectionError,
onDisconnect,
onMessage
)
```
正如你所见,用回调函数写会变得十分笨拙。你需要把所有的功能函数按特定的顺序传给`.connect`来执行。但是将上面所写的功能用事件来实现,就会变成这样:
```js
var chatClient = require('my-chat-client').connect()
chatClient.on('connect', function() {
// have the UI show we are connected
})
chatClient.on('connectionError', function() {
// show error to the user
})
chatClient.on('disconnect', function() {
// tell user that they have been disconnected
})
chatClient.on('message', function() {
// show the chat room message in the UI
})
```
这种写法和回调函数很像,但是运用了高大上的`.on`功能,它会让一个回调函数‘监听’一
gitextract_g5wgeig8/ ├── LICENSE.md ├── code/ │ ├── 1.js │ ├── 2.js │ ├── 3.js │ ├── 4.js │ └── number.txt ├── readme.es.md ├── readme.fr.md ├── readme.md ├── readme.pt-br.md ├── readme.ru.md ├── readme.zh-cn.md └── readme.zh-tw.md
SYMBOL INDEX (5 symbols across 4 files)
FILE: code/1.js
function addOne (line 5) | function addOne() { myNumber++ } // define the function
FILE: code/2.js
function addOne (line 7) | function addOne() {
FILE: code/3.js
function addOne (line 7) | function addOne(callback) {
function logMyNumber (line 15) | function logMyNumber() {
FILE: code/4.js
function takesOneSecond (line 1) | function takesOneSecond(callback) {
Condensed preview — 13 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (229K chars).
[
{
"path": "LICENSE.md",
"chars": 108,
"preview": "Creative Commons Share Alike (do whatever, just attribute me)\nhttp://creativecommons.org/licenses/by-sa/2.0/"
},
{
"path": "code/1.js",
"chars": 163,
"preview": "// cd code/\n// node 1.js\n\nvar myNumber = 1\nfunction addOne() { myNumber++ } // define the function\naddOne() // run the f"
},
{
"path": "code/2.js",
"chars": 349,
"preview": "// cd code/\n// node 2.js\n\nvar fs = require('fs')\nvar myNumber = undefined // we dont know what the number is yet since i"
},
{
"path": "code/3.js",
"chars": 320,
"preview": "// cd code/\n// node 3.js\n\nvar fs = require('fs')\nvar myNumber = undefined\n\nfunction addOne(callback) {\n fs.readFile('nu"
},
{
"path": "code/4.js",
"chars": 275,
"preview": "function takesOneSecond(callback) {\n setTimeout(after, 1000)\n function after() {\n console.log('done with one, on to"
},
{
"path": "code/number.txt",
"chars": 1,
"preview": "1"
},
{
"path": "readme.es.md",
"chars": 24781,
"preview": "# El Arte de Node\n## Una introducción a Node.js\n\nEste documento está destinado a aquellos lectores que saben al menos un"
},
{
"path": "readme.fr.md",
"chars": 42033,
"preview": "# The Art of Node\n## Une introduction à Node.js\n\nSi vous souhaitez découvrir Node et que les connaissances énoncées ci-a"
},
{
"path": "readme.md",
"chars": 37977,
"preview": "# The Art of Node\n## An introduction to Node.js\n\nThis document is intended for readers who know at least a little bit o"
},
{
"path": "readme.pt-br.md",
"chars": 40987,
"preview": "# A arte do Node\n\n## Uma introdução ao Node.js\n\nEste documento é destinado à leitores que sabem no mínimo algumas das co"
},
{
"path": "readme.ru.md",
"chars": 42363,
"preview": "\n# Поэзия Ноды\n## Введение в Node.js\n\nДанный материал предназначен для читателей, которые уже имеют представление о:\n\n- "
},
{
"path": "readme.zh-cn.md",
"chars": 18947,
"preview": "# Node的艺术\n## Node.js入门\n\n本文档假定读者已经懂了以下的两样东西:\n\n- 懂得至少一种编程语言。例如:JavaScript,Ruby,Python,Perl或其他编程语言。如果你还不是程序员,你不懂编程语言,你可以阅读["
},
{
"path": "readme.zh-tw.md",
"chars": 16248,
"preview": "# Node 的藝術\n## Node.js 入門\n\n本文件假設讀者已經懂了以下的兩樣東西:\n\n- 至少懂得一種程式語言。例如:JavaScript,Ruby,Python,Perl 或其他程式語言。如果你還不是程式設計師,你也不懂程式語言,"
}
]
About this extraction
This page contains the full source code of the max-mapper/art-of-node GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 13 files (219.3 KB), approximately 61.4k tokens, and a symbol index with 5 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.