자바스크립트 콜백함수 관리 아이디어

Vue를 공부하다가 갑자기 생각나서 글 싸지른다.

자스에서는 가변인자 값은 가져올 수 있는데, 인자명은 못가져온다.
일단 자스에서 개체 까는 API인 ReflectProxy가 있는데,
대체적으로 개체 속성과 생성 관리를 담당할 뿐이다. 물론 유용하긴 하지만.
함수 내에서도 인자를 까는 메소드도 없고, API도 없다.
함수 내 arguments 개체 또한 인자값을 가져올 뿐이고.
최신인 ES2017에서도 이를 대응할 API는 없다…

물론 불가능한 건 아니다. 한가지 확실한 점은, 네이티브 함수(예: Object, Array 등)만 아니면
Function.prototype.toString() 메소드를 실행 시 함수 전체가 까발려진다.
거기서 함수명과 인자, 함수 내용이 모두 나오게 된다. 그 어떤 브라우저든 간에.

그래서 이를 이용해 인자 이름을 가져올 수 있는 방법이 있다.
출처: How to get function parameter names/values dynamically?

var STRIP_COMMENTS = var STRIP_COMMENTS = /(\/\/.*$)|(\/\*[\s\S]*?\*\/)|(\s*=[^,\)]*(('(?:\\'|[^'\r\n])*')|("(?:\\"|[^"\r\n])*"))|(\s*=[^,\)]*))/mg;
var ARGUMENT_NAMES = /([^\s,]+)/g;
function getParamNames(func) {
  var fnStr = func.toString().replace(STRIP_COMMENTS, '');
  var result = fnStr.slice(fnStr.indexOf('(')+1, fnStr.indexOf(')')).match(ARGUMENT_NAMES);
  if(result === null)
     result = [];
  return result;
}

그러하다. 함수 내용을 파싱해서 코멘트 제거하고 인자명만 쏙 가져올 수 있다.

getParamNames(getParamNames) // returns ['func']
getParamNames(function (a,b,c,d){}) // returns ['a','b','c','d']
getParamNames(function (a,/*b,c,*/d){}) // returns ['a','d']
getParamNames(function (){}) // returns []
getParamNames(function (a=4*(5/3), b) {}) // returns ['a']

완벽하게 대응이 되는 것 같진 않아보여도 대부분 케이스에 대응이 가능하다.
굳이 대응 안되는 케이스가 있다면… 아무래도 화살함수(Arrow Function)가 되겠는데,
(a=>b).toString() 호출하면 크롬의 경우 "a=>b" 이렇게 나온다…
가장 쉬운 대응 방법은 babel로 강제 변환해서 써버리는 것이다… asyncawait 나오면 묵념…

추가로 명명된 가변인자(function(...args))도 대응할 수 없다. 근데 일반 가변인자처럼 대응이 더 어렵다. 패스.

어쨌든, 이제 내가 말하고자 하는 아이디어 예제를 내겠다.
document sandbox 예제다. 함수인자 까는 함수는 위에 것을 그대로 활용한다.

function sandbox(func){
    var anames = getParamNames(func);
    anames = anames.map(function(method){
        return function(){ return document[method].apply(document, arguments); };
    });
    return func.apply(window, anames);
}

sandbox(function(createElement, getElementById, createTextNode){
    var a, b;
    a = createElement('p');
    a.innerHTML = "hello world!";
    document.body.appendChild(a);
    b = getElementById('out');
    b.appendChild(createTextNode('YAY~!'));
});

참고로 document 객체의 모든 요소는 참조를 허용하지 않기 때문에, 어쩔 수 없이 함수로 감싸 꼼수를 썼다.
실행 결과는 jsfiddle 에서 볼 수 있다.
만약 Array.prototype.map 메소드가 실행되지 않는 구닥다리 브라우저의 경우는… jQuery.map() 으로 알아서 수정해서 테스트 해보라.

뭐 내가 말하려는 게 대충 이런 식이다. 이런 샌드박스형 콜백을 활용하면 더 유연한 콜백 대응이 가능할 거라 믿기 때문이다.
근데 왜 ECMA에서는 인자명에 관심을 가지지 않는걸까? 의문을 가지며 이것으로 마치도록 하겠다.

끗.

composite / 2017년 9월 7일 / Piss Development / 0 Comments

Javascript 파이프라인

어찌보면 나도 간과한 일일 수도 있다.
Javascript 로 열심히 삽질하다 보면 역시 콜백 늪에 안빠져본 자스 개발자는 없을 것이다.
이런 콜백 지옥을 빠져나가기 위해 여러 패턴이 도입되었고, 그 중 대표적인 게 Promise 패턴, Generator, 그리고 async/await 이다.

마침 Play.node() 라는 컨퍼런스가 이미 진행했었고, 공개된 발표자료 중 바로 한눈에 들어온 세션이 있었는데,
그게 바로 Session 3. Pipe: 콜백지옥의 또 다른 거짓 선지자 였다.

그리고 콜백 지옥을 빠져나갈 수 있다는 여러 선지자들, 그리고 세션 발표자가 이를 개선하기 위해 만든 또다른 선지자를 소개하는 시간이었다.
필자는 여기에 참여하지 못해 이 세션의 처음과 끝이 어땠는지는 잘 모르겠지만, 자스 개발자들은 뭔가 너무 차별화된 형식으로 접근하려는 시각이 눈에 띄었다.

그렇다. 너무 차별화되어 다르게 보일 수 있지만 결국 똑같은 패턴.

그게 바로 작업 흐름 관리이다. 영어로 Task flow management.
이를 관리하기 위해 보통 제공되어 사용하는 패턴이 바로 Pipeline pattern 이다.
작업 단위 간 통신을 위해 꼬리를 물고 무는 패턴.

자바스크립트는 싱글 쓰레드다. 그렇기 때문에 얻을 수 있는 이점이 있지만 이를 위해 잃은 많은 것들이 있다.
얻을 수 있는 이점이 바로 비동기 이다. 자스는 비동기에 능하다. 어떤 작업 흐름을 미꾸라지처럼 빠져 나가는 재주를 지녔다.

다른 언어에서도 이런 미꾸라지같이 작업 흐름을 마칠 수 있는 이점을 수용하려 하고 있었고, 이렇게 생겨난 것이
자바의 Future<T> 와 닷넷의 Task<T> 이다. 그리고 닷넷 4.5 에는 asyncawait 문법으로 비동기 작업 흐름 관리에 종지부를 찍을 것 같았다.
자스에서도 이런 종지부를 받아들여 ES7에 들어올 예정이긴 하지만… 언제 들어올지는 아직 모른다. 그렇기에 기대에 부응하지 못하고 오늘도 자스는 작업 흐름을 관리하고 있다.

동시성과 비동시성을 합쳐서 여러 케이스로 작업 흐름을 관리하는 업무는 의외로 많다.
하지만 많은 개발자들은 이를 동기적으로 처리하려고 한다. 왜냐, 그게 편하고 순서있고 보기도 편하기 때문에.

하지만 위 소개된 세션을 통해 이런 자스의 고충을 이해할 수밖에 없는 이유가 있다. 아니. 이해해야 할 수밖에 없다.
바로 자스는 아까 말했듯 싱글 스레드이다. 아까 말했듯이 자스는 어찌보면 너무 많은 것을 잃은 것만 같다.
쓰레드를 여러 개 사용할 수 있는 자바나 닷넷 등이 아니다 보니 쓰레드 단위로 Pipeline 을 갖는다는 것은 매우 어려운 일이다.
그래서 위 세션처럼 비동기 방식의 장점을 살려 바로 이벤트를 통해 작업 흐름을 관리하는 파이프라인을 구현한 것이다.
여기서 가장 핵심 공통점은 바로 작업 간 데이터를 주고받아야 한다. 그리고 이 때문에 구현한 것이다.
자스는 작업 흐름 관리를 위해 콜백 간에 데이터를 주고받아야 하는 일이 많다. 그렇다 보니 전통적인 방법으로는 콜백 지옥이 발생하는 것이다.

그렇다. 자스도 결국 파이프라인 패턴 써야 한다. 작업끼리 물고 물고 늘어진다. 이건 어느 언어나 업무 흐름에 피할 수 없는 숙명인 것이다.
자스는 작업을 관리하는 방식이 다를 뿐, 결국 작업은 파이프라인인 것이다. 어쩌면 동시에 해야 할 수 있고, 그리고 동시에 모두 끝나야 대기탔던 작업 해야 하고.

WE ARE THE HELLO WORLD.

참고자료

Play.node() 발표자료 http://d2.naver.com/news/2602887
자바 : 파이프 스트림과 쓰레드간 데이터 교환 http://javacan.tistory.com/entry/72
닷넷 : C# 쓰레드 이야기: 11. 이벤트(Event) http://www.hanbit.co.kr/network/view.html?bi_id=360

콜백지옥의 또 다른 거짓 선지자 관련 또다른 참고자료

Node.js Flow (part 1) – Callback Hell vs. Async vs. Highland http://blog.vullum.io/javascript-flow-callback-hell-vs-async-vs-highland/
Node.js Flow (part 2) – Fibers and Generators http://blog.vullum.io/nodejs-javascript-flow-fibers-generators/
yortus/asyncawait – Callback heaven for Node.js with async/await https://github.com/yortus/asyncawait

composite / 2016년 1월 6일 / Piss Development / 0 Comments

[JS] String.prototype.replace() 문자열 함수 대체를 허하노라!

제목은 좀 거창하겠지만 그냥 String.prototype.replace 메소드의 함수 사용법 정리다.

먼저 콜백 함수 구조는 아래와 같다.

function(match, p1, [p2... p9, offset, string){
    // insert your code here.
}

인자는 이렇게 알면 된다.

  • match: RegExp.prototype.match() 메소드 실행 후 나오는 배열의 첫자리[0]에서 정규식에 매치된 문자열 전체를 불러온다. 그걸 가져다 쓴다. ($0)
  • p1, p2... p9: 정규식의 그룹 매치 ($1 ~ $9) 인자이다. 그룹 매치는 최대 9개 불러올 수 있으며, 늘어날수록 두번째 기준 인자에서 늘어난다.
  • offset: 정규식이 매치된 원래 문자열 대비 위치이다. 예를 들어 abcd 에서 bcd 매치가 될 경우 offset 값은 1이 된다. 당연히 0부터 시작이다.
  • string: 정규식을 검색하기 위해 사용된 문자열 전체를 불러온다.

여기서 주의해야 할 점은 p1, p2... 인자인데, 이들 때문에 offset이 몇번째 인자인지를 가늠할 수 없다. 당신이 그룹 매치를 몇번 하냐에 따라 인자 위치가 달라지기 때문이다.

이제 거청하지도 않은 설명 끝났으니 예제를 통해 사용해보도록 하겠다.
간단한 템플릿 치환 예제이다.

var tmpl = '내 이름은 [[name]] 이며 나이는 [[age]] 이다.',
    binding = {name: '홍길동', age: 20},
    regex = /\[\[(\w+)\]\]/g,
    callback = function(match, name, offset, string){
        return binding[name] || '그딴거없다';
    };

console.log(tmpl.replace(regex, callback));
//결과: "내 이름은 홍길동 이며 나이는 20 이다."

간단하지 아니한가?

여담:

String.prototype.replace 메소드는 원체 느리다. 가장 빠른 방법이 일반 문자열 replace이다. 어자피 한번만 갈아 끼우기 때문에 빠를 수밖에 없다.
이는 문자열 대체냐 함수 대체나 상관없이 비슷한 성능을 내준다.
그러니 업무상 템플릿 엔진에 성능 신경쓸 시간에 걍 체념하고 이거 쓰거나 어떤 이가 만들어준 템플릿 엔진을 쓰자.

ECMAScript 6 의 새로운 문법인 템플릿 문자열이 있다. 사용법은 아래와 같다.

var binding = {name: '홍길동', age: 20},
    tmpl = `내 이름은 ${binding.name} 이며 나이는 ${binding.age} 이다.`;

console.log(tmpl);

PHP 쓰거나 .NET 4.6 쓴 사람에겐 익숙한 문법이긴 하지만 역따옴표(`)를 쓴다는 게 특이점이라 하겠다.
ES6 트랜스파일러인 Babel.js 는 위 문법을 쓰면 아래와 같이 변환한다.

'use strict';

var binding = { name: '홍길동', age: 20 },
    tmpl = '내 이름은 ' + binding.name + ' 이며 나이는 ' + binding.age + ' 이다.';

console.log(tmpl);

그렇다. 문자열 합치기(string concatenation)를 사용하여 간단하고 성능 좋게 해석했다.
아직은 이 기능이 네이티브로 들어간 모습은 못봤다. 그래서
트랜스파일링 시간과 표현 시간이 합쳐져서 아직까지 성능은 느리게 나온다.
직접 테스트하고 싶으면 http://jsperf.com/es6-string-literals-vs-string-concatenation 가면 된다.

그럼 이만.

composite / 2015년 12월 23일 / Piss Development / 0 Comments

Symbol 프로그래밍?

https://en.wikipedia.org/wiki/Symbol_(programming)

심볼. 굳이 우리말을 쓰자면 기호. 기호 개발. (뭔가 어색하다?)

오늘 페북에서 ECMAScript 6 표준에 Symbol이 정의되어 누군가가 MDN에 번역해 주었다.
Symbol – Javascript | MDN
심볼. 아마 자바, 닷넷, 자스 개발자 등에게 어찌보면 생소한 개념일 수 있다.
하지만 루비 개발자나 Object-C 개발자는 이미 있기 때문에 알고 있을 것이다.
이 심볼 개발방법은 여러 스크립트 언어 등에서 채택한 개발론이다.

간단하게 설명하자면, “가장 유일한 식별자”다.
뭐?
루비(Ruby)의 심볼이란?

정의는 한 번. 더 이상 변경할 수 없는 값이다.
여기까진 상수와 비슷한 개념이다.
그렇다면 값 비교 시 “A” 와 “A”가 같다? 심볼은 그딴거 없다.
그렇다. 심볼의 값은 일종의 사람만이 식별하기 위해 존재하는 값일 뿐.
문자열 값은 리터럴을 정의할 때마다 메모리가 늘어난다. 설령 변수를 지정하던 상수를 쓰던.
간단하게 생각해보자.
“A” “BC” “DEF”… 이들은 언제 바뀌지 못하기 때문에 불명확한 메모리를 할당받으며 서 있다.
당연히 그런 만큼 메모리를 잡아먹는다.
하지만 심볼은 딱 정해진 메모리만큼만 먹는다. 바뀔 일도 없기 때문에. 확장할 일도 없고.
그러니 메모리 애끼는 효과가 있다.

그렇다면 어따가 쓰냐고?
가장 쓰임새가 많이 쓰이는 곳이 바로 “해시 값”을 다루는 데에 쓰인다.

JS에 새로 정의된 Symbol을 통해 예제 하나 뿌리겠다.
ES6 Symbol Test 예제

var obj = {};
var a = Symbol("a")

obj[a] = "a";
obj[Symbol.for("b")] = "b";
obj["c"] = "c";
obj.d = "d";

for (var i in obj) {
   console.log(i); // logs "c" and "d"
}

console.log(obj[a]); //logs "a"

심볼 “a” 란 해시 키에 “a” 값을 넣었다.
근데… 반복문에는 나타나지 않는다.
그렇다. 주소 값이니 나오지 않을 수밖에.
대신에 명시적으로 해시 키를 정의하면 가져올 수 있다.
이런 이득이 있다는 것이다.
그렇다면 이런 특징으로 얻을 수 있는 이득이 뭐가 있을까?

간단하다. hidden 키와 값을 넣을 수 있는 그런 개발이라면 모두 가능하다.
일종의 private identifier 인 셈이다.

자. 이제. 자바와 닷넷도 이런 개념이 존재하냐고 물어보는 사람이 있을 것이다.
당연히 없다. 근데 자바와 닷넷은 문자열에 한해 인터닝(Intern) 이라는 개념이 있다.

자바의 String.intern() String.intern()은 메모리를 아낄 수 있다?

  • String pool에 있는 각종 문자열에 equals해서 같은게 있다면 그 놈을 반환하고,
  • 같은게 없다면 String pool에 String object를 추가하고, 추가한 놈을 반환한다.

즉, String 객체를 리터럴로 관리하여 메모리 절약을 꽤하는 개념이다.
그렇다 보니 아래와 같은 단점이 존재한다.

  • 우선 String 객체를 하나 만들어야 한다.
  • String의 equals 메소드를 이용해서 String pool에 있는 놈을 찾아서 비교해야 한다. ( 시간이 걸림 )
  • String pool에 들어 갔으므로, 더 이상 GC(가비지컬렉션)의 대상이 될 수 없다. ( 메모리 관리 불가 )

그렇기 때문에 적재적소에 잘 관리해야 한다는 점이 있다. 그래도 같은 문자열을 객체로 정의하여 메모리 쳐묵보단 낫다.

참고로 닷넷도 아주 동일한 개념이다. String.Intern() 메소드 쓰는 건 매한가지이며 동일하기 때문에 별도의 설명은 생략하겠다.

자. 자바와 닷넷이 문자열을 관리하는 방법이 여기서 나온다. 리터럴은 자바나 닷넷이나 내부 풀을 따로 운영하여 저장한다. GC에 걸리는 걱정 없이.
(물론 new String 처럼 객체로 만들었다면 걸릴 각오는 해야 하지만.)

뭔가 삼천포로 빠진 것 같다.
하지만 메모리를 아껴서 빠르고 유연한 개발을 꾀하는 개발자는 있다.
이럴 때 필요한 것이 뭐고, 뭘 알아야 하는지는 개발자의 사명인 것이다.
그러기 위해 이 포스트를 올렸다.
그럼 이제…

끗.

composite / 2015년 11월 17일 / Piss Development / 0 Comments

내가 한번 추천해보는 웹 개발자를 위한 Visual Studio 확장 모음

페북 그룹에 Visual Studio 웹 개발자 추천 확장 모음 링크를 올렸길래 나도 올려본다. 여기에 기재된 확장 도구를 포함하여 내가 쓰고 왜 쓰는지 알리고자 글을 쓴다.
내가 설치한 확장 목록을 이름순으로 볼 수 있다보니 알파벳별로 정렬하는 점 양해 바란다.
아, MS에서 만든 확장은 제외다.

Code Alignment

이름만 봐도 눈치챈 사람도 있을 것이다. 말로 하긴 힘드니 아래 코드로 뭔 프로그램인지 알려주겠다.

    person.HomeTown = "Brisbane"; 
    person.FirstName = "Chris";                
    person.Surname = "McGrath";                
    person.Age = 24;                           
    person.Occupation = "Software Developer";  

=>  person.HomeTown   = "Brisbane";
=>  person.FirstName  = "Chris"; 
=>  person.Surname    = "McGrath"; 
=>  person.Age        = 24; 
=>  person.Occupation = "Software Developer"; 

올드비 개발자들(특히 C/C++ 개발자)에게 단비같은 확장도구인 데다가 무료이다. 도네이션웨어라는 점.
더이상 설명이 필요있나?

ColorSchemeSelector

ColorSchemeSelector

그저 단순한 색상 추출 도구라면 내가 블로그 보다 말았고 그냥 넘어갔겠지만, 이녀석은 그저 단순한 색상 추출기를 뛰어넘어 색상 혼합별로 색상을 추천받아 추출할 수 있다는 점에서 특히 웹 개발자와 디자이너에게 좋은 도구가 될 것이다.
아, 물론 무료다.

Git Diff Margin

Git Diff Margin

Git로 버전관리를 한다면 해당 줄에 바뀐 점을 이렇게 실시간으로 표현해준다는 점이 되겠다. 자주 바뀌는 일이 많은 버전관리 개발자라면 유용할 것이다.
이 확장 또한 링크된 블로그에 소개되어 있으며, 무료이다.

Grunt Launcher

프론트엔드 개발자라면 반드시 한번씩은 들었을 Grunt. 패키징 자동화로 유명한 Grunt와 스케줄별 자동화를 지원하는 Gulp, 프론트엔드의 패키지 매니저인 Bower 명령어까지 지원해준다.
나처럼 node.js를 수동으로 포터블로 설치한 환경이라면 사용 시 세팅에 유의하라.
무료라고. 소개됐다고.

Image Optimizer

프론트 엔드를 위한 확장이 여기 하나 또있다. Visual Studio 자체 지원 이미지 최적화 도구가 있다면 믿겠는가?
같은 이미지에서 이미지 사이즈를 줄여주는데, 자세한 내용은 이미지 최적화 기법 구글 검색 ㄱㄱ.
이미 node.js 등으로 이미지 최적화 확장이 있다면 비교해달라. 난 아직 비교 안해봤다.
무료다.

Mexedge Stylesheet Extension

간단하게 말하면, 스타일시트 소스를 트리구조로 시각화하는 도구다. 프론트엔드 개발자에게는 상당히 편리한 도구다.
확장 링크로 들어가서 스샷을 보면, 그저 단순한 그런 도구가 아니다. 심지어는 파일 내 클래스 목록처럼 표시까지 해준다.
블로그에서도 소개되어 있다. 3명이 기업 운영하고 있는 것으로 보이긴 한데 일단 무료니 그냥 써 주자.

MixEdit

지금 소개하는 확장은 내가 블로그에서도 소개한 바 있으며, 유일하게 무료가 아닌 평가판 확장이다.
Sublime Text를 접하다가 Visual Studio로 개발하다보면 답답하지 않는가? 멀티커서와 멀티셀렉트가 지원되는 확장, 변수를 한꺼번에 바꿀 수 있다면 얼마나 좋을까?
그런 목마름을 Visual Studio에서도 적셔주는 그런 확장 되시겠다.
평가판이긴 하지만 사용기능과 기간에 제한은 없다. 단지, Visual Studio 실행 후 처음 MixEdit 기능을 수행 시 구매 권유 창이 뜰 뿐이다.

Suggested Extensions

얜 좀 재밌는 확장이다. 블로그에 소개되긴 했는데 댓글에 소개된 확장인데, 파일 확장자별로 사용할 수 있는 Visual Studio 확장을 소개시켜주는 확장 되시겠다.
예를 들면 yaml 같은 파일들. IntelliJ IDEA 같은 개발 툴 쓴 사람은 알겠지만 JetBrains 에서는 확장자별로 지가 확장 추천을 해준다. 그런 비슷한 거다.
무료다.

Web Essentials 2015

만약 웹 개발자인 당신이 Visual Studio를 쓰고 있을 때, 이 확장을 쓰고 있다면 이 확장 제작자에게 큰 절을 해야 한다. 블로그에서도 소개도니 웹 개발자 필수 확장!
웹 개발에 모든 것을 제공해주는 확장이다. CSS, HTML, JS 편집에 날개를 달아주며, CoffeeScript, LESS, Sass 같은 확장 언어 편집과 Grunt, npm, bower 등의 설정 편집에 유용한 도구를 제공하는 웹 개발 만능 확장이다.

Visual Studio 2015 사용자에게 주의점은 소스 파일을 Minify하거나 Bundling으로 합치거나, Sass 및 LESS 컴파일 기능을 따로 확장으로 뺐다는 점에 유의해야 한다. 없다고 해매지 말고 내가 링크 소개할 테니 다운 받아라. 이 확장도 무료고 아래 확장도 무료다. 저거 제작자 만나면 반드시 큰 절 해라.

Bundler & Minifier
Web Compiler

나는 여기까지 추천 확장 목록으로 썼다.
여러분의 추천 확장이 있다면, 서슴없이 공유하여 서로 즐거운 개발 세상을 만들어가는 주역이 되길 바란다.
싫어? 싫음 시집가.
끗.

composite / 2015년 9월 9일 / Piss Development / 0 Comments

ES6 Generator 와 ES7 Generator의 차이점?

ES6 Generator

ES6의 Generator 는 Generator body가 .NET 3.5 의 Enumerable과 Java의 Iterator를 섞은 느낌.

function *foo(){
    for(var i=1;i< =10;i++){
        yield i;
    }
}

for (var v of foo()) {
    console.log(v);
}

그러나 일반적인 Iterator와는 달리 ES6의 Generator는 .next() 메소드 호출이 무제한 가능하다.
따라서 .next()를 통해 얻은 값에서 done:true 인 것으로 필터링 해야 한다.
만약 자바처럼 while(b = a.next()) 이런 식으로 반복문을 돌면 무한 반복이 된다.
왜냐면 a.next() 가 다 돌았다고 해도 계속 마지막 값을 전달하는 스펙 때문이다.
수정 : 모두 호출한 다음 next()를 호출하면 다음 yield 값을 불러오는데 없으면 value가 undefined 나온다. 물론 done:true 는 여전하다.

var a = foo(), b;
while(!(b = a.next()).done)
    console.log(b);

이런 측면에서 ES6 Generator는 기존 개발자들에게 Iterator 와는 다른 혼란이 올 수도 있다.
게다가 비동기를 쓰려면 인라인 함수도 Generator 구문을 사용해야 하며,
비동기 연동은 Promise 객체를 사용해야 하고, spawn 함수가 필요하다.
여러가지로 비동기 사용이 번거로워 계륵같은 구문이 아닐 수 없다.

spawn 함수 1
spawn 함수 2

사용 예제

//제목과 챕터별 내용을 외부 경로에서 비동기로 출력하는 예제
//getJSON 함수는 Promise 패턴을 사용한 Ajax 함수라고 가정한다.
function loadStory() {
  return spawn(function *() {
    try {
      let story = yield getJSON('story.json');
      addHtmlToPage(story.heading);
      for (let chapter of story.chapterURLs.map(getJSON)) {
        addHtmlToPage((yield chapter).html));
      }
      addTextToPage("All done");
    } catch (err) {
      addTextToPage("Argh, broken: " + err.message);
    }
    document.querySelector('.spinner').style.display = 'none';
  });
}

ES7 Generator

ES7의 Generator 는 .NET 4.5 의 await와 async 구문을 채용한 듯 한 느낌을 줄 것이다.
사실 사용법도 크게 다르진 않다. 게다가 비동기에 대한 배려가 잘 적용되어 있다.

//제목과 챕터별 내용을 외부 경로에서 비동기로 출력하는 예제
//getJSON 함수는 Promise 패턴을 사용한 Ajax 함수라고 가정한다.
async function loadStory() {
  try {
    let story = await getJSON('story.json');
    addHtmlToPage(story.heading);
    for (let chapter of story.chapterURLs.map(getJSON)) {
      addHtmlToPage((await chapter).html);
    }
    addTextToPage("All done");
  } catch (err) {
    addTextToPage("Argh, broken: " + err.message);
  }
  document.querySelector('.spinner').style.display = 'none';
}

ES6과 달리 spawn 함수가 필요없다. 하지만 비동기인 만큼 Promise 객체를 사용해야 한다는 사실은 변함없다.
하지만 번거로운 spawn 함수가 없는 데다가 코드가 상당히 간결해졌다. 그래서 ES6 스펙이 그냥 ES7로 넘어갔으면 하는 희망사항이 생기기도 한다.

사용법도 간단하다.

(async function() {
  await loadStory();
  console.log("Yey, story successfully loaded!");
}());

단지 실행시에도 Generator 구문을 써야 한다는 점만 빼면 간단하게 실행이 가능하다.

그럼 자바스크립트 개발자의 이해를 돕기 위해 .NET 4.5 에서 추가된 await/async 예제를 보도록 하자.
Async 및 Await를 사용한 비동기 프로그래밍

//msdn.microsoft.com 의 내용 길이를 가져오는 비동기 함수
async Task<int> AccessTheWebAsync()
{ 
    // HTTP 클라이언트 선언
    HttpClient client = new HttpClient();

    // GetStringAsync 함수는 mdsn.microsoft.com 의 HTML 내용을 비동기로 받아둔다.
    // Task 클래스는 JS의 Promise와 동일한 역할을 하며, (자바는 Future<t>) 일단 작업을 받아낸다.
    Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

    // 일단 작업은 받아냈기 때문에 기다릴 필요 없이 해당 구문으로 넘어간다. 기타 할 것들.
    DoIndependentWork();

    // await를 사용하여 getStringTask 의 작업이 끝날 때까지 AccessTheWebAsync 메소드는 기다린다.
    // 만약 getStringTask 의 작업이 끝나면 urlContents 에 결과값을 전달한다.
    // 이게 끝날 때까지 다음 절차로 넘어갈 수 없다.
    string urlContents = await getStringTask;

    // 이제 위의 비동기 작업이 끝났으니 작업을 마무리할 시간.
    // 비동기 작업을 통해 받아온 urlContents 의 문자열 길이를 출력함으로서 작업을 마친다.
    return urlContents.Length;
}

여기서 공통점이 있다면 Promise 특성과 Generator의 성격을 안다면 알겠지만,
await 구문에 있는 메소드나 Promise 객체가 then 을 통하여 값을 전달할 때 까지는 다음 작업을 수행할 수 없다는 것이다.
ES6의 yield 과는 다르다. yield 구문은 그냥 쌩 값을 반복하듯이 내보내기 때문에 직접 핸들링 해야 한다는 차이점이 있다.
이 차이점을 이해했다면 ES7의 Generator 가 더 진보되고 편해졌다고 느껴질 것이다.

미안하다. 나도 다쓰고 이해시키는 것에 실패했다. 조만간 부가설명이나 글 수정을 통해 개선하겠다.
게다가 일도 바빠서 여기까지.

참고자료

The Basics Of ES6 Generators
ES7 async functions

composite / 2015년 4월 6일 / Piss Development / 0 Comments

ECMAScript 6 Harmony 를 네 브라우저에 돌려봐라!

나 참.. 기분 존나 나쁘네.

뭐? CoffeeScript? TypeScript? 어쩌고 저째? 자바스크립트가 죽을 거라고?

난 동의 안한다. 제아무리 자바스크립트를 편하게 만들어도 오리지날이다. 결국 그들도 자스로 움직인다. 제아무리 편해도.

스칼라가 결국 자바에서 돌아가기 위해 자바 코드로 생성해서 컴파일 하는 것처럼 말이다.

튜닝의 끝은 순정이란 말이 괜히 나오는게 아니지.

그래서 소개한다. 니 브라우저에 직접 ECMA 6 을 적용할 기회를 내가 선사해 주겠다. 2가지 프로젝트가 있다.

1. Traceur

구글신은 미쳤다. 이번에 소개할 피로젝트는 자바 2명 타요가 아닌 외계인 2명 타요 해서 ECMA 6을 몸소 체험할 수 있는

Traceur 를 소개한다.

프로젝트 페이지는 https://github.com/google/traceur-compiler

이 스크립트 컴파일러는 ES6 을 당신 브라우저에 돌릴 수 있게 한다.

일단 IE 8은 안된다. 쳇. 최소한 8이라도 지원해주지.

크롬과 불여우는 일단 된다. 올ㅋ

Traceur 가 지원하는 ECMA 6 기능이다.

일단 여태 나오고 알려진 것들을 지원한다.

하지만 이 ES6 하모니를 쓸 때 몇가지 주의할 점이 있다.

알다시피 ES6은 확정된 표준이 아니다. 특히 클래스와 모듈이 그 대표적인데, 이들이 어떻게 바뀔지는 장담을 못하겠다.

제발 안바뀌길 바래라.

뭐.. 그래봐야 기반 스크립트 (타입스크립트 등) 또한 아직까지 안정화된 버전을 내놓지 못하고 있기 때문에

물론 커피스크립트는 상당히 안정화 되고 쓰는 사람 많은거 안다.

근데 뭐가 좋다 말을 못하겠지만, 그래도 그런 스크립트는 표준에 넣지 못할 것이다.

난 커피스크립트가 자바의 스칼라처럼 생각하지만, 그래도 스칼라도 많이 쓰지 않는가? 물론 갈라파고스 한국은 빼고.

난 표준을 만들고 따르는 주의자긴 하지. 자바스크립트는 아직까지는 강력하기 때문에. 단지 좀 귀찮고 짱나서 그렇지.

어쨌든, ES6 을 직접 체험해보고자 한다면, 이 컴파일러를 이용해 제작된 ES6Fiddle 을 사용하라.

http://www.es6fiddle.net/

ECMAScript 6 이 어떻게 돌아가는지 알 수 있을 것이다.

2. continuum 

그에 비해 이 ES6 컴파일러는 커뮤니티의 참여로 만들어졌다. 그다음 낫고, IE 8부터 지원해주기 때문에 우왕굳.

프로젝트 사이트는 https://github.com/Benvie/continuum

체험 사이트는 http://benvie.github.io/continuum/

현재 구현된 기능들이다.

  • 통합 할당 및 인자
  • 가변 처리자 및 배열 초기자
  • 가변 인자
  • 클래스와 상속
  • 화살표식 함수(람다식) (.NET 의 람다식과 동일한 형식)
  • 블록 단위 변수
  • 새로운 Math 함수
  • 새로운 Object 함수
  • 새로운 String 함수
  • concise methods in object literals
  • 열거 및 삭제 가능한 프로토타입
  • Map, Set, 그리고 WeakMap (가비지 컬렉션이 현실화되지는 않았음)
  • 열거자와 for…of 반복문
  • 템플릿
  • 모듈과 imports, exports
  • 내장 ‘@std’ 모듈 module std = '@std' 또는 import call from '@function'
  • 생성기
  • 프록시와 리플렉션
  • Symbols with syntactic @name support
  • 형식화된 배열Typed Arrays
  • Object.observe (es-next/es7)
  • 인자 기본값
  • 꼬리물기 호출 최적화
  • 배열 초기화 식 (부분 지원)

아래 기능은 아직 구현이 안되어 있으며 추후 지원될 예정이라 한다.

  • 생성기 식
  • 이진 데이터 api (structs, etc.)
  • 프로미즈 (내가 Feature request 했음.)

물론 프로미즈같은 경우 promisejs 또는 q 로 해결은 가능하기 때문에 커버는 해줄만 하다.

ECMA 6 기능에 목이 말랐다면 지금 바로 체험하라.

아참, 마지막으로 ES6의 새로운 기능을 한글로 잘 정리한 위키 페이지가 있어 이걸 소개하고 쿨하게 끝내겠다.

http://wiki.codekin.com/index.php/ECMAScript_%ED%95%98%EB%AA%A8%EB%8B%88

끝이다.

추신 업데이트 사항 : Traceur 외에 나머지 ES6 컴파일러는 몇달동안 활동이 없다. 그냥 Traceur 써라. 진자끝.

composite / 2014년 2월 25일 / 미분류 / 0 Comments

지연된 객체 (Deferred Object) 만들기 – 오리지날 JS편

오랜만에 골때리게 한번 팁을 날려보겠습니다.

jQuery 1.5 에서 획기적이지만 잘 안쓰는 게 있죠.

바로 지연된 객체(Deferred Object) 입니다.

이 객체의 위력을 정말 느껴본사람 빼고는 잘 안쓰죠.

이놈의 패턴이 어떻냐..

$.get(‘/serv/get.php’,null,function(){

     alert(‘뭘 받아온듯.’);

});

이 기존 패턴과

$.get(‘/serv/get.php’)

    .success(function(){

        alert(‘뭘 받아온듯.’);

    });

이 제이쿼리에서 제안한 패턴과 똑같은 효과를 줍니다.

뭐.. 느낌상 패턴은 당연히 틀리죠.

분명 Ajax는 비동기 스크립트입니다. 하지만 동기한 것 처럼 뭔가 착각을 불러일으키기도 하고.

바로 비동기 스크립트를 이렇게 눈에 보기 좋게 꾸며 놓는다는 장점이 있습니다.

node.js 개발하다보면 이벤트 중점적이다 보니 종종 비동기 쓸때 이런 패턴이 발생합니다.

var mongodb = require(‘mongodb’),

Db = mongodb.Db;

var db = new Db(‘test_db’, new Server(process.env[“MONGODB_HOST”], process.env[“MONGODB_PORT”], {}));

db.open(function(err, db) {

     db.collection(“test_collection”, function(err, collection) {

          collection.find({“cmd”:cmd}, {“sort”:”order”}, function(err, cursor) {

               cursor.each(function(err, item) {

                   if (item != null) {

                       // Do something

                   }

                   if (item != null) {} // 반복문 끝

                });

           db.close();

           });

  });

});

오우 쉣. 함수안에 함수안에.. 너무 지저분합니다.

하지만 제이쿼리가 제안한 지연된 객체 패턴으로 간다면 저걸?

db.open()

.collection(‘test_collection’)

.find({“cmd”:cmd}, {“sort”:”order”})

.fetch(function(err,cursor){

cursor.each(function(err, item) {

if (item != null) {

// Do something

}

if (item != null) {} // 반복문 끝

});

})

.close();

이런 식으로 비동기 스크립팅에 제이쿼리의 최강무기 메서드 체이닝을 구사할 수 있다는 겁니다.

물론 저런 패턴 제공하는 놈은 아직까지 없으니 그대로 따라하지 마시길. 그냥 예를 든거니까요.

그럼 어떤 원리로 하는건지 오늘 골때리게 설명해 드리도록 하겠습니다.

일단 먼저, 동적 클래스의 개념과 클로저 개념을 이해하고 있어야 합니다.

저는 그 이해를 하고 있는 분으로 간주하고 팁을 씁니다. 모르면 문학이님이 떡하니 강좌 올려놨으니 보시길.

..라고 무섭게 얘기했는데. 어렵지 않습니다. 먼저 동적 클래스를 만들 함수를 하나 짜주세요.

fuynction MyDefferd(){

this.fn={};

//초기화 할거 있음 하덩가.

}

그리고 지연된 객체에서 체이닝에 사용할 프로토타입 함수 하나 만들겠습니다.

MyDefferd.prototype.done=function(func){

this.fn.done=func;

};

뭐.. 준비 끝입니다.

그리고 이제 지연된 객체를 리턴할 함수를 하나 만들겠습니다.

그리고 이 함수는 비동기 작업을 할 겁니다. 간단하게 setTimeout 을 쓰겠습니다.

function Deffer(delay){

var deff=new MyDefferd();//아까 만든 지연객체를 동적으로 하나 불러와 주시고.

alert(‘작업 시작!’);

setTimeout(function(){

if(typeof(deff.fn.done)==’function’)

deff.fn.done();//done 함수를 끌어다 씁니다.

},delay*1000);//몇초 후에? 님이 쓴 초 후에.

return deff;//반드시 동적 지연 객체를 반환해줘야 합니다!

}

이것으로 지연객체 패턴을 사용할 수 있는 함수를 쓸 준비가 끝났습니다. 참 쉽죠?

어떻게 쓰냐? 간단합니다. 예를 들어 3초 후에 작업 끝 메시지가 나오도록 꾸며보겠습니다.

Deffer(3).done(function(){

alert(‘작업 끝!’);

});

그럼 처음에 작업 시작이란 경고창이 뜬 다음, 3초 후에 작업 끝이란 경고창이 뜰겁니다.

그렇게 나오면 성공!

어때요. 참 쉽죠?

동적 클래스는 함수 종료 후 클로저 때문에 메모리 다시 반납해 하는걸 개나 줘버라는는 성질 덕분에 deff 함수에서 언제든지 저렇게 동적 클래스 안에 있는 데이터를 잃지 않고 갖다 쓸 수 있습니다.

이걸 이용해서 지연된 객체를 통해 비동기 스크립트 패턴을 동기 스크립트 패턴같이 꾸밀 수가 있는 것이죠.

이런 지연 객체를 응용해서 Ajax는 물론, node.js 에서 할 수 있는 대부분의 비동기 작업에서 여러분의 눈을 정화시키는 패턴을 만들 수 있을 것입니다.

그리고 쿨하게 오늘의 골때리는 팁을 마치겠습니다.

링크 #1은 지연된 객체 패턴을 이용한 동적 스크립트 불러오는 함수입니다.

링크 #2는 이 강좌 예제입니다. 바로 실행되고 또 하고싶음 run 버튼 누르셈.

라이센스 : 해당 강좌에 사용한 기술은 죽써도 밥써도 상관없는 Public Domain. 강좌 자체는 크리에이티브 커먼즈 라이선스

composite / 2013년 9월 16일 / 미분류 / 0 Comments

적응형 가상 스크롤 Adaptive Virtual Scrolling

이번 undefine 이라는 소프트웨어 진흥원 산하 자바스크립트 팀 세미나에서 에서 마지막에 흥미로운 발표를 했다.

바로 네이버 오피스를 만들었다는 한 자스 개발자의 개발기, “자바스크립트, 어디까지 가봤니?” 라는 주제로 발표를 했다.

네이버 오피스를 만들면서 자바스크립트로 아주 그냥 철인 경기를 한 듯한 개발기를 한 그 개발자에게 먼저 경의를 표한다.

누군지 까먹어서 ㅈㅅ. 하지만 그는 정말 대단한 열정으로 자스계의 신의 경지에 올라왔다 해도 과언이 아니라고 말해주고 싶다.

어쨌든 이 발표가 끝나고 내 선배한테 헬프성 문자가 왔는데 그 중 하나가 바로 대용량 그리드 스크롤이 필요하게 생겼단다.

허.. 가는날이 장날인가..

나같은 경우 원리는 이해하나 구현해본 적이 없다. 그렇다고 직접 구현하기엔 여러가지 삽질이 필요했고

그거 생각할 시간은 너무나 부족했다.

그래서 내가 즐겨쓰던 그리드 플러그인인 SlickGrid 를 통해 답변을 찾기로 했다.

그리고 SlickGrid 는 나에게 정말 속 시원한 답변을 주었다.

왜 내가 SlickGrid 를 선택했냐면, 처음으로 대용량 그리드에 대한 스크롤링을 구현하여 몇십만 행의 데이터를 아무렇지도 않게 불러오는 스킬로 전 세계의 위엄을 떨친 그리드이기 때문이다. 게다가 라이센스가 MIT이다.

그리고 그 개발과정도 녹아 있었다. (제작자가 공개한 대용량 데이터 스크롤링 개발과정이 있다. 물론 영문이다.)

https://github.com/mleibman/SlickGrid/issues/22

그리고 그는 대용량 스크롤링을 구현하였고, 그것을 jsfiddle 에 공개햐였다.

http://jsfiddle.net/SDa2B/4/ (영어)

http://jsfiddle.net/wu7zq/ (내가 한글 번역)

이쯤에서 가상 스크롤이 뭔지 알아보자면,

사용자는 아무렇지도 않게 스크롤을 하는데, 스크롤을 하면서 개발자는 스크롤한 위치에 따라 컨텐츠 표시를 대응한다.

이게 가상 스크롤이라고 한다.

작년 웹 디자인 트랜드를 주름잡았던 패럴랙스 스크롤도 가상 스크롤에 해당되며,

SlickGrid 에서 스크롤한 위치만 보여주는 기술도 가상 스크롤이다.

이놈의 영감을 체험해보려면 바로 엑셀 프로그램이 있다.

엑셀은 수백만 행의 데이터를 똥컴에서도 랙없이 보여주는 기술을 가지고 있다.

만약 수백만 행이 렌더링 된 상태였다면 똥컴은 수백만 행에 대한 메모리를 이기지 못하고 뻗고도 남는다.

HTML도 마찬가지로, 눈에 보이는 모든 요소는 메모리에 담게 되며, 그래픽 처리를 하게 된다. 어느 프로그램이나 마찬가지.

그래서 HTML이던 자바던 닷넷이던 씨뿔뿔이던 다 이런 보이는 곳에 대한 대응은 안할래야 안할 수가 없다.

특히, 3D FPS 게임에서 보이는 곳만 렌더링 하는 것이 성능에 엄청난 차이를 보이기 때문에 민감할 수밖에 없다.

이런 류로 중요한 것이다.

제이쿼리 그리드 플러그인인 DataTable 도 한 업체의 도움을 받아 대량의 행도 아무렇지도 않게 보여줄 수 있는 가상 스크롤링을 구현하였다.

이 글을 통해 어떤 원리로 작동되는지 소개되어 있다. (조만간 번역해주겠다.)

https://datatables.net/blog/Introducing_Scroller_-_Virtual_Scrolling_for_DataTables

이리하여 웹 앱이라는 것이 어떤건지 아주 그냥 재대로 실감나게 한 한주가 되었다.

이제 와이프랑 놀아줘야겠다. 내 아내가 지금 삐친 상태라 오늘은 여기까지.

composite / 2013년 7월 27일 / 미분류 / 0 Comments

[javascript] 문자열을 자스 코드로 평가하는 짓거리.

여러분은 문자열을 자스 코드로 평가하는 짓거리를 하는 방법을 들라 하면 대표적으로 eval 들겁니다. 

제목이 이따구냐 들어와봤는데 eval 만 들어도 “아” 할거에요. 

근데.. 문자열을 자스 코드로 바꾸는 방법은.. 의외로 다양합니다. 

IE 전용 방법으로는 document.execScript 메서드가 있습니다. 

new Function(arg1,arg2,argN…,functionBody) 에서 functionBody 가 문자열이어도 함수가 만들어지며 자스 코드로 됩니다. 속살은 네이티브이니 eval 쓰는지 알 턱은 없지만.. 

setTimeout(functionBody,millisecond) 함수에 문자열을 코드로 집어넣는거. 옛날에 자스 해봤다면 쉽게 접해봤을 겁니다. 무서운건 지금도 setTimeout 에다가 문자열 집어넣는 선배님도 봤습니다. 우웩. 

네. eval 은 이미 많이 알려진 “악마”고 차기 ECMA 표준에서 뺄거란 얘기가 무성하게 흘러나왔죠. 

eval의 특징은 해당 스코프의 문자열을 자스 코드로 변환하여 실행하는 특징을 가지고 있습니다. 

스코프 뚫리면 보안은 뭐.. 말안해도 섬뜩할겁니다. 

그러다가 jQuery 에서 globalEval 메서드가 있는겁니다. 이녀석의 특징은 일단 문자열을 자스로 평가하는데 스코프를 무조건 최상위인 window로 잡는 특징이 있습니다. 일단 보안 측면에서는 다행이긴 한데 문자열을 자스 코드로 평가하다니.. 

그러다가 globalEval 메서드를 까봤습니다. 

globalEval: function( data ) { 

    if ( data && rnotwhite.test( data ) ) { 

        // We use execScript on Internet Explorer 

        // We use an anonymous function so that context is window 

        // rather than jQuery in Firefox 

        ( window.execScript || function( data ) { 

            window[ “eval” ].call( window, data ); 

        } )( data ); 

    } 

}, 

window 스코프를 가리키는 eval 악마를 보실 수 있습니다.으헝헝. 

이녀석이 왜 있냐구요? 이녀석도 쓰입니다. ajax 에서 스크립트 불러올때 그 스크립트 실행하기 위해 존재하는 메서드죠. 

그런데 말입니다. 

그런데.. 저는 의아해 했습니다. 좀 더 안전하게 스크립트를 실행하는 다른 방법이 있을까. 

그래서 여러가지 실험을 해봤습니다. 아까 new Function 에서 문자열 받아내는거 아시죠? 

그걸 이용해 봤습니다. 

new Function(“console.log(this);”)(); 

이렇게 해봐서 콘솔 봤더니 this 는 window를 가리킵니다. 

그리고 

function foo(){ 

    new Function(“console.log(this)”)(); 

new foo(); 

이렇게도 해봤더니 this는 여전히 window를 가리켰습니다. 

불여우, 크롬, IE 6,8,9,10 모두 같은 결과가 나왔습니다. 

그렇다면 jquery globalEval을 이렇게 꾸며도 무방할것 같다는 생각이 들었습니다. 

globalEval: function( data ) { 

    if ( data && rnotwhite.test( data ) ) { 

        return void new Function(data)(); 

    } 

}, 

게다가 new Function 은 인자도 받을 수 있습니다. (IE는 모르겠지만) 

스코프는 항상 최상위인 window 를 가리킵니다. 

처음엔 이렇게도 생각해봤습니다. 

globalEval: function( data ) { 

    if ( data && rnotwhite.test( data ) ) { 

        return void setTimeout(data,0); 

    } 

}, 

이렇게 하면 IE의 메모리 누수를 막을 수 있을 것 같은 느낌도 들어서죠. 

이번엔 더 거대하게 생각을 해봤습니다. 아예 스크립트 태그를 만들어 버리는 것도요. 

var script = document.createElement(‘script’); 

script.innerHTML=code+’\n’+//자스 코드 넣고 

    ‘var scripts=document.getElementsByTagName(‘script’);\n’+ 

    ‘document.documentElement.removeChild(scripts[scripts.length-1])’;//스크립트 실행후 DOM 삭제 

document.documentElement.appendChild(script); 

이것저것 생각해봤습니다. 

여러분은 타 스크립트를 가져올때 어떤 방법이 가장 좋을까요? 

물론 원격지 스크립트라면 script 태그가 진리겠죠. 

일단 생각해봅시다. 같은 도메인 안에서 한다고 가정하고. 원격 스크립트를 실행하는 방법이죠. 

동적으로 불러와야 한다는 전제 하에. 

  1. 스크립트 파일을 동적으로 만들어 script 태그 하나 만들어 포함시킨다. 

  2. 스크립트 파일을 Ajax로 불러오고 jQuery globalEval 등으로 실행시킨다. 

  3. 내가 테스트한 방법을 써본다 

<

p>

동적 스크립트 실행. 이대로 괜찮은가? 

참으로 어처구니 없는 일이 아닐 수 없습니다.

composite / 2013년 7월 20일 / 미분류 / 0 Comments