הלינקייה: מגזין חודשי למפתחים

רוצה לשמוע על כל האירועים, המדריכים, הקורסים והמאמרים שנכתבו החודש ?
הלינקייה הינו מגזין חופשי בעברית שמשאיר אותך בעניינים.
בלי ספאם. בלי שטויות. פעם בחודש אצלך בתיבה.

Common Techniques

In this chapter we'll go over some of the things we need in every programming language, and see how they are performed in Node.JS.

Working With Buffers

A buffer is similar to an array of integers, but corresponds to a raw memory allocation happened outside the V8 heap. Normal JavaScript has no support for random access to the device's memory, so they are an addition of Node.
Buffers are used when reading from files, reading packets from the network, and Node.JS modules rely on them.

A Buffer cannot be resized after it's been allocated.

When you want to convert between buffers and JavaScript Strings, keep in mind the a String also includes the character encoding for the characters, so you'll need to specify the charset of the buffer. Here are the available encodings:

  • ascii
  • utf8
  • utf16le
  • ucs2
  • hex

You can create a buffer from a String, an Array, or by specifying an initial size for the buffer. Buffers also support writing and reading data to them, either using designated read/write methods, or simply by treating them like arrays.

For more information about Buffers, refer to the API Docs.

Demo - Using Buffers:

var buf = new Buffer(4);
buf[0] = 0x33;
buf[1] = 0x34;
buf[2] = 0x41;
buf[3] = 0x44;

var text = buf.toString('ascii');

// prints 34AD
console.log( text );

Using Command Line Arguments

The global object in Node is called process, and it provides the data and methods on the current running process. process is shared between all files and modules in a Node application.

It's a good idea to console.dir( process ) to see some of its features. In the following example, I use process.argv to print out all command line arguments the program was started with:

console.log( process.argv );

Note the first is simply node (the process name), and the second is usually the file name or path.

Working With Files

Working with the filesystem in Node can be confusing at first. Because we have no threads, most API calls are non-blocking, which means you provide each function with a callback.

One useful convention is the callback always takes an error object as its first argument. Other arguments depend on the specific function.

To use the Node filesystem API, we need to require('fs'), and the result object provides the filesystem methods.

Although every function has a synced version as well, it is recommended to only use the async API. This way you will never block the web server.

The filesystem API provides many methods to deal with file systems: renaming files, deleting files, getting a file's stats and more. In this short intro, I'd like to introduce the methods required to read and write files.

Reading A File

Use fs.readFile to read a file's contents into a buffer. The function takes a filename, an optional encoding (defaults to utf8), and a callback.
The callback will be called with the file's contents as a Buffer.

Example - Read a file and print the first 10 characters:

var fs = require('fs');

fs.readFile('/etc/passwd', function (err, data) {
  if (err) throw err;
  var first10 = data.toString('utf8', 0, 10);
  console.log(first10);
});

Writing A File

Use fs.writeFile to write a buffer into a file. If the file already exists, the method replaces it. fs.writeFile takes 4 arguments:

  1. A Filename
  2. Data To Write
  3. Optional Encoding (defaults to utf8)
  4. Callback Function

The callback is called with only one argument - an error object. If no error occurred, its value is falsy.

Example - Write a file

fs.writeFile('message.txt', 'Hello Node', function (err) {
  if (err) throw err;
  console.log('It\'s saved!');
});

I/O Steams

Reading or writing a few bytes at a time is usually a better idea for larger files. In Node, we can use Streams to read or write data when the data is not yet completely ready, or is very large.

Use a Read Stream for read operations, and Write Stream for write operations. Both streams can be opened on files, but you can also open streams on network connections, for streaming data to your clients.

fs.createWriteStream and fs.createReadStream are the methods we use to create the streams. Here are two examples for reading and writing streamed data to files.

Example - Write Stream

var fs = require('fs');
 
var out = fs.createWriteStream('output.txt');
 
out.write('Hello\n');
out.write('-----\n\n');
out.write('Node Streams are cool\n');
 
out.end();

Streams emit events when things happen, so in order to read a file from using a Read Stream you'll need to listen on the data event.

Example - Read Stream

var fs = require('fs');

var rs = fs.createReadStream('/etc/passwd');
rs.on('data', function(data) {
  console.log('---');
  console.log( data.toString() );
});

rs.on('close', function() {
  console.log('>>>>>');
});

Sending Email

One nice thing about Node packaging system is that there's a package for almost anything. The day-to-day tasks such as writing Excel sheets, sending emails, communicating with public APIs and many more have a module that makes developers' lives easy.

You can find a list of all Node's modules in https://npmjs.org/. Let's take one module as an example - sending emails. NodeMailer is a popular module for doing that.

After installation, you need to set up a transport and a message, and simply use transport.sendMail(message) to send the email. Here's a short demo:

var nm = require('nodemailer');

var transport = nm.createTransport("SMTP", {
  service: "Gmail",
  auth: {
    user: "user@gmail.com",
    pass: "password"
  }
});


var message = {
  from: 'Me <ynon@ynonperek.com>',

  to: '"You" <ynonperek@yahoo.com>',

  subject: 'Testing Node Mailer',

  html:'<p><b>Hello</b> to myself <img src="cid:note@node"/></p>'+
    '<p>Here\'s a nyan cat for you as an embedded attachment:<br/><img src="cid:nyan@node"/></p>',
};

transport.sendMail( message, function(err) {
  transport.close();

  if ( err ) {
    console.dir( err );
  } else {
    console.log("Sent OK");
  }
});

NodeMailer has a long list of well known services, which includes Hotmail, Gmail, Yahoo, And others. In addition, you can use any SMTP email server.

Getting Data From Other Websites

Node can help you build both Web Servers and Web Clients. On the client side, you can send any HTTP request, get the response and parse it to get data from other web sites.

The module here is named request. It takes a URL and callback (or a more complex options variable as the first argument), reads the data and calls the callback with the returned response data.

Here's how we can use request to read some data from facebook:

var request = require('request');
 
request('http://graph.facebook.com/ynonp', function(err, response, body ) {
  var me = JSON.parse( body );
  console.log( me.id );
});

Note body is the contents of the response body, and checking for err is also a good idea.

Twitter also has a JSON based API, so it's really easy to read data from Twitter as well. Here's a short example:

var request = require('request');
 
request('http://search.twitter.com/search.json?q=israel', 

function(err, response, body ) {

  var data = JSON.parse( body );
  for ( var i=0; i < data.results.length; i++ ) {
    console.log('---');
    console.log( data.results[i].from_user + ':' +
  data.results[i].text );

  }
});