블로그 이미지
윤영식
Full Stacker, Application Architecter, KnowHow Dispenser and Bike Rider

Publication

Category

Recent Post

'Event Machine'에 해당되는 글 1

  1. 2013.07.20 [Node.js] Art of Node 정리1
2013. 7. 20. 12:25 NodeJS/Concept

Smart Dashboard라는 장난감을 하나 만들면서 서버단을 Node.js로 코딩을 하고 있다. Node.js에서 가장 햇갈리는 부분 그리고 인식의 전환을 해야하는 것들을 "Art of Node"에서 잘 정리해 주고 있다. Node.js의 핵심은 무엇인지 알아보자.



1. Callback

  - Node.js 는 I/O Platform 이다 : filesystm과 network I/O를 위한 플랫폼이다. Gateway와 같다고 생각해 보자~~ 


  


  - Callback은 node.js에서 나온 개념이 아니라 이미 있던 개념 : C언어에서 "함수포인터"와 같다 

  - Async가 기본이기 때문에 결과에 대한 처리를 요청하는 Callback function을 파라미터로 넘긴다 

  - 다음 예는 undefined가 나온다. Async이기 때문에 addOne() 호출(invoke)하고 바로 console.log(myNumber)으로 이동해 버린다. File I/O보다 Memory I/O가 훨씬 더 빠른다. 

var fs = require('fs') // require is a special function provided by node
var myNumber = undefined // we don't know what the number is yet since it is stored in a file

function addOne() {
  fs.readFile('number.txt', function doneReading(err, fileContents) {
    myNumber = parseInt(fileContents)
    myNumber++
  })
}

addOne()

console.log(myNumber) // logs out undefined -- this line gets run before readFile is done

  - 다음 예가 정확한 예이고 Closure개념을 결합하여 정보를 받아서 출력하고 있다. callback을 addOne 함수의 파라미터로 넘겨서 fs.readFile내부의 doneReading Callback 펑션에서 Closure객체로 callback()을 호출하는 것이다

var fs = require('fs')
var myNumber = undefined

function addOne(callback) {
  fs.readFile('number.txt', function doneReading(err, fileContents) {
    myNumber = parseInt(fileContents)
    myNumber++
    callback()
  })
}

function logMyNumber() {
  console.log(myNumber)
}

addOne(logMyNumber)

  - 이것에 대한 Pseudo Pattern 정리하면 다음과 같다 

function addOne(thenRunThisFunction) {
  waitAMinute(function waitedAMinute() {
    thenRunThisFunction()
  })
}

addOne(function thisGetsRunAfterAddOneFinishes() {})

  - Callback을 하다보면 간혹 이런 가독성이 떨어지는 문구를 볼 수 있다. 이에 대한 해결은 Defer/Promise 를 사용한다. Java 진영에서는 Future라고 한다. 주로 Async 프로그래밍시 Callback을 사용할 때의 문제점을 serial하게 해결할 수 있는 do -> then -> error 처리가 가능함 

a(function() {
  b(function() {
    c()
  })
})



2. Events

  - Node.js는 Even Machine (about ruby on rails or twisted of Python) 이다 

  - Observer Pattern을 사용하고, Publish/Subscribe 개념을 갖는다 

  - on 펑션을 통하여 Subscribe 하고, emit 펑션을 통하여 Publish 한다

  - 하기 예는 Subscribe하여 처리할 Handler를 Callback 펑션 정의(Definition)을 미리한다. 그리고 connect() 펑션에 인자로 넣는다 

var chatClient = require('my-chat-client')

function onConnect() {
  // have the UI show we are connected
}

function onConnectionError(error) {
  // show error to the user
}

function onDisconnect() {
 // tell user that they have been disconnected
}

function onMessage(message) {
 // show the chat room message in the UI
}

chatClient.connect(
  'http://mychatserver.com',
  onConnect,
  onConnectionError,
  onDisconnect,
  onMessage
)

  - 위 예를 다른 형태로 변경하면, 즉, connect() 메소드에서 작용하는 원칙은 다음과 같다. on(<EventName>, <Callback Function>) 를 통하여 Subscribe하는 것과 동일하다 

var chatClient = require('my-chat-client').connect()

chatClient.on('connect', function() {
  // have the UI show we are connected
}) 

chatClient.on('connectionError', function() {
  // show error to the user
})

chatClient.on('disconnect', function() {
  // tell user that they have been disconnected
})

chatClient.on('message', function() {
  // show the chat room message in the UI
})

  


3. Stream

  - Stream I/O 를 통하여 끊김없이 file system, network I/O를 수행할 수 있다. 성능의 병목없이 물흐르듯 데이터가 흘러간다. 

  - Substack사의 Stream Handbook을 보자

  - stream module은 노드의 코어모듈이다 : require('stream')

  - 하기 코드는 data.txt 파일읽는 것이 다 끝나면 Callback의 data로 전달이 된다. 이때 data.txt파일이 크다면 그만틈의 메모리를 사용하게 되고 병목이 생길 수 있다. Async 방식을 고려한다면 성능상의 문제를 야기할 수 있겠다. data.txt파일 읽으면서 http응답 병목발생. 

var http = require('http');
var fs = require('fs');

var server = http.createServer(function (req, res) {
    fs.readFile(__dirname + '/data.txt', function (err, data) {
        res.end(data);
    });
});
server.listen(8000);
  - 위의 예제를 Stream 방식으로 변경한다. 파일을 읽어서 일정 크기단위(Chunk)로 요청한 Client로 응답을 준다.  
var http = require('http');
var fs = require('fs');

var server = http.createServer(function (req, res) {
    var stream = fs.createReadStream(__dirname + '/data.txt');
    stream.pipe(res);
});
server.listen(8000);
  - .pipe() 의미

.pipe() is just a function that takes a readable source stream src and hooks the output to a destination writable stream dst: - 읽을 소스 스트림 src가 있고 쓸 스트림으로 output을 연결해 주는 펑션일 뿐이다

src.pipe(dst)

  - 스트림 체이닝(Chaining)의 표현
a.pipe(b).pipe(c).pipe(d)

위 아래 동일 표현

a.pipe(b);
b.pipe(c);
c.pipe(d);

the command-line to pipe programs

a | b | c | d 

  - 스트림의 5가지 : readable, writable, transform, duplex, classic
  - Readable : pipe의 읽을 소스에 대한 처리를 별도로 해주어 output destination으로 보낸다. readableStream.pipe(dst) 
var Readable = require('stream').Readable;

var rs = new Readable;
rs.push('beep ');
rs.push('boop\n');
rs.push(null);

rs.pipe(process.stdout);
$ node read0.js
beep boop
  - Writable : 소스를 읽고서 표현하는 output에 대하여 별도로 지정한다. src.pipe(writableStream)
var Writable = require('stream').Writable;
var ws = Writable();
ws._write = function (chunk, enc, next) {
    console.dir(chunk);
    next();
};

process.stdin.pipe(ws);
$ (echo beep; sleep 1; echo boop) | node write0.js 
<Buffer 62 65 65 70 0a>
<Buffer 62 6f 6f 70 0a>
  - classic방식은 node v0.4 버전때 처음 나왔다. 
  - duplex는 a.pipe(b).pipe(a) 와 같이 양방향 파이프
  - transform은 read/write filter 이다

 


4. Modules

  - 모듈개념으로 npm(Node Package Manager)를 통하여 필요한 것을 설치한다 : 34,000 개가량의 모듈이 등록되어 있음

  - 모듈 찾기 npm search <ModuleName> : npm search pdf

  - package.json 안에 해당 모듈이 사용하는 다른 모듈 정보와 모듈의 일반 정보(이름, 버전, 저장소등)가 있다 : npm init

  - node코드에서 require('some-module'); 를 찾는다. require 동작 순서

  • if a file called some_module.js exists in the current folder node will load that, otherwise - 현재 디렉토리에 있는지 찾는다 
  • node looks in the current folder for a node_modules folder with a some_module folder in it - 현재 디렉토리에 node_modules 디렉토리가 있는지 찾고 있으면 그 밑으로 some_module 폴더가 있는지 찾는다  
  • if it doesn't find it, it will go up one folder and repeat step 2 - 위 두개다 찾지 못하면 윗쪽 폴더로 가서 두번째 처럼 다시 node_module 폴더를 찾아간다 


  • <참조>

      - art of node 원문

      - 함수 포인터에 대한 이해

      - Closure 알아가기

      - NHN이 이야기하는 함수형 언어와 클로져 이야기

      - Substack사의 Stream Handbook

    posted by 윤영식
    prev 1 next