Bert Belder


aka @piscisaureus


node and libuv

  • Flow control
  • Stability
  • Debugging / what's going on inside node?
  • Threading
  • NPM

http://bit.ly/wrongcode

            
var http = require('http');
var cache = {};

function curl(url, cb) {
  if (cache[url])
    return cb(null, cache[url]);

  var data = '';

  http.get(url, function(res) {
    res.setEncoding('utf8');

    res.on('data', function(s) {
      data += s;
    });

    res.on('end', function() {
      cache[url] = data;
      cb(null, data);
    });

    res.on('error', function(err) {
      cb(err);
    });
  });
}

// Usage:
curl('http://www.google.com', console.log);
            
          
            
var waiting = 2;

stream1.on('close', function(err) {
  if (--waiting === 0)
    nextStep();
});

process.on('exit', function() {
  if (--waiting === 0)
    nextStep();
});
            
          
            
TransformStream.prototype.pull = function(data, cb) {
  // Call the user-supplied _transform(data, cb) function.
  var sync = true;

  var transformCb = function(data) {
    if (sync) {
      process.nextTick(function() {
        cb(data);
      });
    } else {
      cb(data);
    }
  };

  this._transform(data, cb);

  sync = false;
}
          
        
          
{
  http.get('http://2048.org', function(err, result) {
    console.log(result);
  });

  // Do this in parallel:
  setTimeout(function() {
    throw new Error('Take out the trash!');
  }, 9000);
}

WAIT HERE ();

// And then when that is all done:
if (error) {
  clean_everyting_up();
  console.log('Oh noes!');
} else {
  console.log('Beer!' + result);
}
          
        
          
zone.create(function() {
  http.get('http://nyan.cat', function(err, result) {
    zone.return(result);
  });

  setTimeout(function() {
    throw new Error('Take out the trash!');
  }, 9000000);

}).setCallback(function(err, result) {
  if (err)
    throw err;
  console.log(result);
});
          
        
          
zone.create(function() {
  http.get('http://zombo.com', function(err, result) {
    if (err) throw err;
    zone.return(result);
  });

  setTimeout(function() {
    throw new Error('Take out the trash!');
  }, 9000 * 1e6);

}).then(function(result) {
  console.log(result);

}).catch(function(err) {
  console.log('Not good! ' + err);
});
          
        
            
zone.create(function() {
  // Within the outer task.

  zone.create(function() {
    // Within a nested task.
    fs.stat(...);
    http.get(...);

  }).setCallback(err, result) {
    // Back in the outer task
    if (err) throw err;
    clearTimeout(timeout);
    zone.return(result + 1);
  });

  var timeout = setTimeout(function() {
    // In the outer task too.
    throw new Error("It's too slow");
  }, 100);

}).setCallback(function(err, result) {
  // In the global task.
});
            
          
            
zone.create(function OuterTask() {
  zone.create(function InnerTask() {
    setTimeout(function() {
      throw new Error("Oh noes!");
    });
  });

}).setCallback(function(err, result) {
  throw err;
});
            
          
Error: Oh noes!
    at Zone. (D:\x\a.js:6:13)
    at Zone.self.apply (D:\x\node_modules\zone\lib\Zone.js:440:23)
    at processQueues (D:\x\node_modules\zone\lib\scheduler.js:52:12)
    at process._tickCallback (node.js:343:11)
In zone: InnerTask
    at Zone.create (D:\x\node_modules\zone\lib\Zone.js:519:10)
    at Zone.OuterTask (D:\x\a.js:3:8)
    at Zone.create (D:\x\node_modules\zone\lib\Zone.js:519:10)
    at Object. (D:\x\a.js:2:6)
    at Module._compile (module.js:449:26)
    at Object.Module._extensions..js (module.js:467:10)
    at Module.load (module.js:349:32)
In zone: OuterTask
    at Zone.create (D:\x\node_modules\zone\lib\Zone.js:519:10)
    at Object. (D:\x\a.js:2:6)
    at Module._compile (module.js:449:26)
    at Object.Module._extensions..js (module.js:467:10)
    at Module.load (module.js:349:32)
    at Function.Module._load (module.js:305:12)
    at Function.Module.runMain (module.js:490:10)
    at startup (node.js:124:16)
    at node.js:807:3

// Download 3 websites in parallel
// Assume we've already thunkified this in a reasonable way.

co(function*() {
  var p1 = http.get('http://www.google.com/')
               .pipe(fs.createWriteStream('google.html'));
  var p2 = http.get('http://www.bing.com/')
               .pipe(fs.createWriteStream('bing.html'));
  var p3 = http.get('http://www.yahoo.com/')
               .pipe(fs.createWriteStream('yahoo.html'));

  yield [p1, p2, p3];
});

// Download 3 websites in parallel
// Assume we've already thunkified this in a reasonable way.

co(function*() {
  try {
    var p1 = http.get('http://www.google.com/')
                 .pipe(fs.createWriteStream('google.html'));
    var p2 = http.get('http://www.bing.com/')
                 .pipe(fs.createWriteStream('bing.html'));
    var p3 = http.get('http://www.yahoo.com/')
                 .pipe(fs.createWriteStream('yahoo.html'));
                 
    yield [p1, p2, p3];

  } catch (err) {
    // Clean up the http.get's?
    // Clean up the write streams?
  }
});

// Download 3 websites in parallel

try {
  yield zone.create(function*() {
    http.get('http://www.google.com/')
        .pipe(fs.createWriteStream('google.html'));
    http.get('http://www.bing.com/')
        .pipe(fs.createWriteStream('bing.html'));
    http.get('http://www.yahoo.com/')
        .pipe(fs.createWriteStream('yahoo.html'));
  });

  // All succesfull.

} catch (err) {
  // Failure
}
            
// Streams with yield

yield stream.write('hello', callback);
yield stream.end();

var data;
while (data = yield stream.read())
  console.log(data)
            
          

Check out zones!

http://github.com/strongloop/zone

http://strongloop.com/strongblog/announcing-zones-for-node-js/

Questions?

@piscisaureus