2. Profile
● 삼성전자 소프트웨어센터
Web Convergence Lab.
● 블로그
Inside.JS (http://www.nodejs-kr.
org/insidejs)
3. var fs = require('fs')
Synchronous Programming
, path = './sync.txt';
var stats = fs.statSync(path);
if (stats == undefined) {
// read the contents of this file
var content = fs.readFileSync(__filename);
}
var code = content.toString();
// write the content to sync.txt
var err = fs.writeFileSync(path, code);
if(err) throw err;
console.log('sync.txt created!');
console.log(‘Another Task’);
4. var fs = require('fs')
Asynchronous Programming
, path = './async.txt';
// check if async.txt exists
fs.stat(path, function(err, stats) {
if (stats == undefined) {
// read the contents of this file
fs.readFile(__filename, function(err, content) {
var code = content.toString();
// write the content to async.txt
fs.writeFile(path, code, function(err) {
if (err) throw err;
console.log('async.txt created!');
});
});
}
});
console.log(‘Another Task’);
5. Node.js programming is not easy.
var open = false;
setTimeout(function () {
open = true;
}, 1000);
while(!open) {
// wait
}
console.log('opened!');
6. Nested Callback Problem
async1(function(input, result1) {
async2(function(result2) {
async3(function(result3) {
async4(function(result4) {
async5(function(output) {
// do something with output
});
});
});
});
})
7. Flow Control Problem
for(var i = 1; i <= 1000; i++) {
fs.readFile('./'+i+'.txt',
function() {
// do something with the file
}
);
}
do_next_part();
8. Why Flow Control?
• Asynchronous Programming
• Issues
– Doing a bunch of things in a specific order
– Knowing when task is done.
– Nested Callback
– Collecting result data
9. Flow Control Pattern
• Serial Execution
• Parallel Execution
• Limited Parallel Execution
10. Serial Execution
Start
Task1
Task2
Task3
Continue when tasks
complete
12. Flow Control Libraries
• Async – providing various control function
• Step – simple and easy to use
• Slide – used in the npm client code
• Seq
• Nue
•…
13. Node.js Coding Conventions
• Two kinds of functions :
– Action Function : Take action
– Callback Function : Get results
• Action functions
– last argument is always a callback function
• Callback functions
– first argument is always an error or null.
14. Action Callback
Function Result Function
(Action Function Developer) (Action Function User)
15. Action Function Example
function actor (some, args, cb) {
// last argument is callback
// optional args:
if (!cb && typeof(args) === "function")
cb = args, args = [];
// do something, and then:
if (failed) cb(new Error("failed!"))
else cb(null, optionalData)
}
16. Action Callback
Function Result Function
Action Function과 Callback
Function 사이는 결과를 어떻게 넘길 지에 대
한 인터페이스가 명확히 규정되어 한다.
17. Action Function Example
// return true if a path is either
// a symlink or a directory.
function isLinkOrDir (path, cb) {
fs.lstat(path, function (er, s) {
if (er) return cb(er);
return cb(null,
s.isDirectory() ||
s.isSymbolicLink());
});
} isLinkorDir
Result cb
fs.lstat _cb
er, s er, result
18. Usecases : Parallel Execution
● I have a list of 10 files, and need to read all of
them, and then continue when they're all done.
● I have a dozen URLs, and need to fetch them all,
and then continue when they're all done.
●I have 4 connected users, and need to send a
message to all of them, and then continue when
that's done.
19. function asyncMap (list, fn, cb_) {
var n = list.length
, results = []
, errState = null;
function cb (er, data) {
if (errState) return;
if (er) return cb(errState = er);
results.push(data);
if (--n === 0) // 모든 리스트 처리 완료시
return cb_(null, results);
}
// action code
list.forEach(function (l) {
fn(l, cb);
});
}
20. asyncMap
list
result
중간 결과 저 cb_
장
fn cb
err, err, result
data
21. Usecases : AsyncMap
function writeFiles (files, what, cb) {
asyncMap(files,
function (f, cb_) {
fs.writeFile(f,what,cb_);
}, cb_는 asyncMap의 내부 함수임
cb
);
}
writeFiles([my,file,list], "foo", cb);
writeFiles
asyncMap
files cb
list
fn cb_
err
23. function asyncMap(list, fn, cb_) {
var n = list.length
, results = []
, errState = null;
function cbGen (i) {
return function cb(er, data) {
if (errState) return;
if (er)
return cb(errState = er);
results[i] = data;
if (-- n === 0)
return cb_(null, results);
}
}
list.forEach(function (l, i) {
fn(l, cbGen(i));
});
}
24. usecase: Serial Execution
• I have to do a bunch of things, in order.
Get db credentials out of a file, read the data
from the db, write that data to another file.
• If anything fails, do not continue.
25. function chain (things, cb) {
(function LOOP (i, len) {
if (i >= len)
return cb();
things[i](function (er) {
if (er)
return cb(er);
LOOP(i + 1, len)
})
})(0, things.length)
}
27. var fs = require('fs');
var async = require('async');
Async Module Example
var path = './async.txt';
async.waterfall([
// check if async.txt exists
function(cb) {
fs.stat(path, function(err, stats) {
if (stats == undefined) cb(null);
else console.log('async.txt exists');
});
},
// read the contents of this file
function(cb) {
fs.readFile(__filename, function(err, content) {
var code = content.toString();
cb(null, code);
});
},
// write the content to async.txt
function(code, cb) {
fs.writeFile(path, code, function(err) {
if (err) throw err;
console.log('async.txt created!');
});
}
28. Step Module Example
Step(
function readSelf() {
fs.readFile(__filename, 'utf8', this);
},
function capitalize(err, text) {
if (err) throw err;
return text.toUpperCase();
},
function showIt(err, newText) {
if (err) throw err;
console.log(newText);
}
);
29. Step Module Example
Step(
// Loads two files in parallel
function loadStuff() {
fs.readFile(__filename, this.parallel());
fs.readFile("/etc/passwd", this.
parallel());
},
// Show the result when done
function showStuff(err, code, users) {
if (err) throw err;
console.log(code);
console.log(users);
}
)