Stay Hungry. Stay Foolish. Don't Be Satisfied.

기술 뉴스 #26 : 15-03-01

웹개발 관련

그 밖의 프로그래밍 관련

  • Reconciliation Proposal : Node.js와 io.js가 다시 합쳐질 움직임을 보이고 있다. 이 문서는 io.js에서 작성한 문서로 Node.js와 io.js가 합쳐진 프로젝트를 대비한 드래프트 문서로 두 프로젝트가 아직 합쳐지는 것으로 결정되거나 한 것은 아니고 각 조직 등을 어떻게 운영할지 등이 정리된 문서이다.(영어)
  • Introducing gRPC, a new open source HTTP/2 RPC Framework : Google 내부에서 사용하던 HTTP/2 RPC 프레임워크인 gRPC를 오픈 소스로 공개했다.(영어)
  • Introducing Origami Live and Origami 2.0 : 페이스북이 만든 프로토타이핑 도구인 Origami가 프로토타입을 iPhone, iPad에서 실행할 수 있는 Origami Live 앱과 새 버전인 Origami 2.0을 공개했다. 2.0에서는 iOS, Android, web으로 code export도 가능하고 Sketch도 지원한다.(영어)
  • io.js Roadmap : io.js의 로드맵을 계속 정리해서 공개하는 페이지이다.(영어)

IT 업계 뉴스

볼만한 링크

  • Side projects : Redis를 만든 Salvatore Sanfilippo가 사이드 프로젝트의 중요성을 강조한 글이다. Redis 자체도 사이드 프로젝트로 시작한 것이고 메인프로젝트를 하더라도 시간을 더 효율적으로 사용하기 위해서 사이드 프로젝트를 해야 하고 이를 통해 더 큰 프로젝트를 만들 수 있다는 이야기에 동감한다.(영어)
  • 푸시 메시지 타이밍 찾기 : 서비스에서 모바일로 Push 메시지를 보낼 때 사용자의 로그인 세션 시간을 기반으로 최적화해서 보내는 방안을 정리한 글이다. Push의 비용은 전송에 드는 물리 비용이 아니라 고객이 느끼는 매체 피로감이라는 부분에 크게 동감하고 접근 방법과 구현할 때 고민해야 한 부분이 정리되어 있어서 읽어볼 가치가 크다.(한국어)
  • Full Stack Engineer에 대하여 : 최근에 왠지 모르게 이슈가 되는 단어인 Full Stack 개발자에 대한 글로 Full Stack 개발자가 어떤 사람이고 그에 대한 장단점이 무엇인지를 잘 정리한 글이다.(한국어)

프로젝트

  • Stetho : Facebook에서 공개한 안드로이드 애플리케이션에 크롬 개발자 도구를 연결해서 디버깅할 수 있는 브릿지다.
  • CSS Stats : 웹사이트 주소를 입력하면 CSS를 분석해서 규칙이나 폰트의 종류 등을 시각적으로 정리해서 보여준다.
  • jq : Mac이나 Linux에서 사용할 수 있는 도구로 sed처럼 JSON 데이터에서 원하는 내용을 찾을 수 있는 커맨드라인 도구다.

버전 업데이트

2015/03/01 19:08 2015/03/01 19:08

Q promise로 차례대로 비동기작업 실행하기

Node를 많이 사용하지만 Promise를 많이 쓰는 편은 아니다. 물론 I/O가 많은 서버개발을 하다 보면 비동기로 인해서 코드가 엉망이 되는 문제가 꽤 많기도 하고 Callback hell에 빠지는 경우도 종종 있지만, 보통은 Callback을 선호하는 편이다. 일부 특수한 케이스에서 Promise가 해결해주는 부분이 있긴 하지만 전체적으로는 Callback에 비해서 Promise가 뭔가 크게 해결해 준다고 생각해 본 적은 거의 없다. 보통은 Promise가 필요할 때 q를 사용하지만, 일부 범위에만 한정해서 쓰고 있다가 이번에 Sequelize를 쓰다 보니 Promise를 많이 사용하게 됐다.

Promise에서 불만인 부분이 코어에서 Promise를 쓰기 시작하면 다른 부분까지 전파된다는 점인데 이러다 보니 Promise로 로직을 해결해야 하는 부분이 나타났다. 비동기로 I/O를 다룰 때 가장 어려운 경우 중 하나가 동기처럼 순서가 있다거나 어떤 종료 시점을 확인해야 한다거나 할 때인데 이번에 비슷한 경우가 발생해서 Promise로 이를 해결하는 코드를 작성해 봤다.

상황은 간단하다. 아이템이 동적인 배열이 있고 이 배열을 하나씩 꺼내서 비동기로 작업을 해야 한다. 각 작업은 연결되어 있으므로 비동기이지만 차례대로 발생해야 한다. 배열 전체를 동시에 작업하고 완료 처리하면 된다면 Q.all()등을 사용하면 되지만 이번엔 차례대로 처리해야 했다. 다행히 q의 문서에 순서대로 처리하는 예시가 나와 있었다.

var Q = require('q');

var list = [
 {id: 1, name: 'name1'},
 {id: 2, name: 'name2'},
 {id: 3, name: 'name3'},
 {id: 4, name: 'name4'},
 {id: 5, name: 'name5'}
];

var asyncJob = function(i) {
  var deferred = Q.defer();
  setTimeout(function() {
    console.log(list[i]);
    deferred.resolve(i+1);
  }, 1000);
  return deferred.promise;
};

list.reduce(function(prev, curr) {
  return prev.then(asyncJob);
}, Q.resolve(0))
.then(function() {
  console.log('completed');
}); 

asyncJob은 비동기 작업을 시뮬레이트하기 위한 임시 함수로 내부에서 setTimeout을 사용했으므로 복잡한 비동기 작업이 있더라도 이 안에서 작성하면 된다. 기본적으로 Array.prototype.reduce를 사용해서 차례대로 처리하는 방식인데 then()으로 넘겨서 다음 작업으로 하나씩 처리하게 된다. 여기서는 reduce의 방식을 이용해서 파라미터로 배열의 인덱스를 전달해서 하나씩 증가하면서 배열의 다음 아이템을 처리하도록 했다.

이를 실행하면 다음과 같이 1초마다 로그를 출력하면서 차례대로 실행이 된다.

{ id: 1, name: 'name1' }
{ id: 2, name: 'name2' }
{ id: 3, name: 'name3' }
{ id: 4, name: 'name4' }
{ id: 5, name: 'name5' }
completed

관련해서 내용을 찾아보다가 Stackoverflow에서 비슷한 답변을 보게 되었다. 여기서는 재귀를 통한 상태머신을 사용하고 있었는데 이러한 접근이 좀 더 그럴듯해 보여서 위 답변을 참고해서 재작성을 해보았다.

var Q = require('q');

var list = [
 {id: 1, name: 'name1'},
 {id: 2, name: 'name2'},
 {id: 3, name: 'name3'},
 {id: 4, name: 'name4'},
 {id: 5, name: 'name5'}
];

var asyncJob = function(v, a) {
  var deferred = Q.defer();
  setTimeout(function() {
    console.log(v);
    deferred.resolve(1);
  }, 1000);
  return deferred.promise;
};

function next(idx) {
  if (idx > list.length -1) { return Q(true); }
  return asyncJob(list[idx]).then(function(result) {
    return next(idx+ 1);
  });
}

next(0).then(function() { 
  console.log('completed');
});

next()에 초깃값(여기서는 인덱스값)을 전달하고 비동기 작업을 수행하면서 재귀 호출을 하면서 배열이 끝나면 종료하도록 처리했다. 이 코드를 실행하면 결과는 앞과 같게 나온다.

2015/02/16 03:43 2015/02/16 03:43