3. Promise
var File = require('file');
var promise = File.read('mydata.txt');
promise.addCallback(function (data) {
// process data
});
promise.addErrback(function (err) {
// deal with error
})
4. – Ryan Dahl -
‘promise대신 최종 인수 콜백을 사용하도록 하고, 보다
나은 추상화 계층을 구축하는 것은 사용자 라이브러리에
맡기도록 하겠다.’
Promise 의 제거
Node 0.1.30
5. 최종 인수 콜백
모든 비동기 메서드는 마지막 인수로 콜백 함수를 받음
콜백의 첫번째 인수는 항상 error 개체
Last Argument Callbacks
6. 최종 인수 콜백 구현 예시
var obj = function() { };
obj.prototype.doSomething = function(arg1, arg2_) {
var arg2 = typeof(arg2_) === 'string' ? arg2_ : null;
var callback_ = arguments[arguments.length - 1];
callback = (typeof(callback_) == 'function' ? callback_ : null);
if (!arg2)
return callback(new Error('second argument missing or not string'));
callback(arg1);
}
var test = new obj();
test.doSomething(‘test', ‘this’, function(err,value) {
if (err) throw err;
console.log(value);
});
7. 최종 인수 콜백의 역할
마지막 인수가 함수임을 보증
오류가 발생한 경우 Node Error를 생성하여 반환
오류가 발생하지 않으면 메서드의 결과를 전달하여 콜백 호출
8. 중첩 콜백
!
var fs = require('fs');
try {
fs.readFile('./apples2.txt','utf8', function(err,data) {
if (err) throw err;
var adjData = data.replace(/[A|a]pple/g,'orange');
fs.writeFile('./oranges.txt', adjData,function(err) {
if (err) throw err
});
});
} catch(err) {
console.error(err);
}
Nested Callbacks
9. // get list of files
fs.readdir('./data/', function(err, files) {
// for each file
files.forEach(function(name) {
// modify contents
fs.readFile('./data/' + name,'utf8', function(err,data) {
if (err) throw err;
var adjData = data.replace(/somecompany.com/g,'burningbird.net');
// write to file
fs.writeFile('./data/' + name, adjData, function(err) {
if (err) throw err;
// log write
writeStream.write('changed ' + name + 'n', 'utf8', function(err) {
if(err) throw err;
});
});
});
});
});
콜백 스파게티, 죽음의 피라미드
(Pyramid of Doom)
13. var fs = require('fs'), Step = require('step');
try {
Step (
function readData() { // 비동기 함수
fs.readFile('./data/data1.txt', 'utf8', this);
},
function modify(err, text) { // 동기 함수
if (err) throw err;
return text.replace(/somecompany.com/g,'burningbird.net');
},
function writeData(err, text) { // 비동기 함수
if (err) throw err;
fs.writeFile('./data/data1.txt', text, this);
}
);
} catch(err) {
console.error(err);
}
콜백 대신에 this를 전달
첫 번째 함수를 제외한 모든 함수는 첫 번째 매개변수로 error를 요구
에러는 예외로 처리
14. …생략…
try {
Step (
function readDir() {
fs.readdir(_dir, this);
},
function readFile(err, results) {
if (err) throw err;
files = results;
var group = this.group();
results.forEach(function(name) {
fs.readFile(_dir + name, 'utf8', group());
});
},
function writeAll(err, data) {
if (err) throw err;
for (var i = 0; i < files.length; i++) {
var adjdata = data[i].replace(/somecompany.com/g,'burningbird.net');
fs.writeFile(_dir + files[i], adjdata, 'utf8',this);
}
} );
} catch(err) {
console.log(err);
}
! 결과가 배열로 그룹화 되어 전달됨
15. 병렬로 실행하기
var fs = require('fs'), Step = require('step'), files;
try {
Step (
function readFiles() {
fs.readFile('./data/data1.txt', 'utf8',this.parallel());
fs.readFile('./data/data2.txt', 'utf8',this.parallel());
fs.readFile('./data/data3.txt', 'utf8',this.parallel());
},
function writeFiles(err, data1, data2, data3) {
if (err) throw err;
data1 = data1.replace(/somecompany.com/g,'burningbird.net');
data2 = data2.replace(/somecompany.com/g,'burningbird.net');
data3 = data3.replace(/somecompany.com/g,'burningbird.net');
fs.writeFile('./data/data1.txt', data1, 'utf8',this.parallel());
fs.writeFile('./data/data2.txt', data2, 'utf8', this.parallel());
fs.writeFile('./data/data3.txt', data3, 'utf8', this.parallel());
} );
} catch(err) {
console.log(err);
}
this.parallel()이 각 함수의 순서를 보장
17. var fs = require('fs'), async = require('async');
try {
async.waterfall([
function readData(callback) {
fs.readFile('./data/data1.txt', 'utf8', function(err, data){
callback(err,data);
});
},
function modify(text, callback) {
var adjdata=text.replace(/somecompany.com/g,'burningbird.net');
callback(null, adjdata);
},
function writeData(text, callback) {
fs.writeFile('./data/data1.txt', text, function(err) {
callback(err,text);
});
}
], function (err, result) {//에러 발생시 처리를 중단하고 완료 콜백 호출
if (err) throw err;
console.log(result);
});
} catch(err) {
console.log(err);
}
18. async.waterfall
……
function readData(stats, file, callback) {
if (stats.isFile())
fs.readFile(_dir + file, 'utf8', function(err, data){
callback(err,file,data);
});
},
function modify(file, text, callback) {
var adjdata=text.replace(/somecompany.com/g,'burningbird.net');
callback(null, file, adjdata);
},
……
async.waterfall([작업 함수 배열, …], 완료 콜백);
파라메터 전달 흐름
callback의 첫번째 인자는 error개체, 각 함수의 마지막 인자는 callback개체
21. 입력
data1.txt : apple
data2.txt : oranges
data3.txt : peaches
!
결과
{ data1: ‘applesn’, data2: 'orangesn', data3: 'peachesn' }
{ 작업명 : 각 작업별 결과, … }
22. Node 스타일
동기보다는 비동기 함수를 사용
2칸 들여쓰기 사용
세미콜론을 사용 / 사용하지 마라
작은 따옴표를 사용
여러 변수 선언시 단일 var 키워드 사용 / 여러 var 키워드 사용
상수는 모두 대문자
변수는 camel case
완전 항등 연산자(===) 사용
함수에 이름 붙이기
라인길이 80자 이하
중괄호는 중괄호를 필요로 하는 것과 같은 줄에서 시작