aka @piscisaureus
node and libuv and strongloop
"Future of asynchronous programming in node"
"The future of node streams. We need to talk"
"Callbacks as our Generations' Go To Statement"
var waiting = 2;
stream1.on('close', function(err) {
if (--waiting === 0)
nextStep();
});
process.on('exit', function() {
if (--waiting === 0)
nextStep();
});
var Url = require('url'),
Http = require('http'),
Fs = require('fs');
function download(url, filename, cb) {
var urlObject = Url.parse(url),
file;
var request = Http.get(urlObject, function(res) {
if (res.statusCode != 200) {
makeCallback(new Error("HTTP Error: " + res.statusCode));
return;
}
file = Fs.createWriteStream(filename);
res.pipe(file);
file.on('error', function() {
file.destroy();
});
file.on('close', function() {
file = null;
makeCallback();
});
});
request.on('error', function(err) {
if (file) file.destroy();
makeCallback(err);
});
function makeCallback(err) {
if (!cb) return;
cb(err);
cb = null;
}
}
Callbacks as our Generations' Go To Statement
try_async(callback) {
// Do async stuff.
// Eventually:
succeed_with 42;
// Or you might:
throw new Error('Вы облажался');
} catch_finally_async(err, result) {
// We get here when all async stuff
// in the try_async block is over.
}
task.create(function(callback) {
// Do async stuff.
// Eventually:
callback(null, 42);
// Or you might:
throw new Error('Вы облажался');
}).setCallback(function(err, result) {
// We get here when all async stuff
// in the try_async block is over.
});
task.create(function(callback) {
// Within the outer task.
task.create(function(callback) {
// Within a nested task.
}).setCallback(err, result) {
// Back in the outer task
if (err) throw err;
callback(null, result + 1);
});
setTimeout(function() {
// In the outer task too.
throw new Error("It's too slow");
}, 100);
}).setCallback(function(err, result) {
// In the global task.
});
fs.readFile('/foo/bar', cb)
fs.readFile = function(path, options, callback_) {
...
function afterRead(er, bytesRead) {
if (er) {
return fs.close(fd, function(er2) {
return callback(er);
});
}
...
}
...
}
fs.readFile = function(path, options, callback_) {
return task.create(function(callback) {
fs.open(path, function(err, fd) {
if (err) throw err;
var result = '', offset = 0;
doRead();
function doRead() {
fs.read(fd, afterRead, offset, 65536);
}
function afterRead(err, data) {
if (err)
throw err;
if (!data.length) // EOF
return fs.close(fd, afterClose);
offset += data.length;
result += data.toString();
doRead();
}
function afterClose(err) {
if (err)
throw err;
callback(null, result);
}
});
}).setCallback(callback_);
};
task.create(function(callback) {
var conn = net.createConnection(80, 'www.google.com');
conn.on('data', function(data) {
callback(null, data);
});
});
var conn = net.createConnection(80, 'www.google.com');
task.create(function(callback) {
conn.on('data', function(data) {
callback(null, data);
});
});
var conn = net.createConnection(80, 'www.google.com');
task.create(function(callback) {
conn.on('data', function(data) {
callback(null, data);
});
conn.on('error', function(err) {
// You'd only need to do this if you actually wanted to
// handle this - because default action is implied:
throw err;
});
});
First tick | ||||||||||
setTimeout | cb | |||||||||
accept | cb | |||||||||
read | cb | |||||||||
read | cb | |||||||||
write | cb | |||||||||
shutdown | cb | |||||||||
accept | cb | |||||||||
read | cb | |||||||||
write | cb | |||||||||
shutdown | cb |
First tick | ||||||||||
setTimeout | cb | |||||||||
accept | cb | |||||||||
read | cb | |||||||||
read | cb | |||||||||
write | cb | |||||||||
shutdown | cb | |||||||||
accept | cb | |||||||||
read | cb | |||||||||
write | cb | |||||||||
shutdown | cb |
task.create(function OuterTask(callback) {
task.create(function InnerTask(callback) {
// beep
}).setCallback(err, result) {
// boop
});
setTimeout(function() {
throw new Error("It's too slow");
}, 100);
}).setCallback(function(err, result) {
throw err;
});
Error: ugly, yellow, no-good keister off my property Task: InnerTask (lib/server.js:52:3) at <anonymous> (lib/index.js:15) at invokeTimer (timer.js:110:21) at TimerWrap.ontimeout Task: OuterTask (lib/index.js:1:13) at Task.<anonymous> (as _complete) (index.js:14:3)
http://github.com/nujs/nu
http://nujs.github.io/nodeland-2013
Bikeshedding workshop!