[ECMAScript 6] Promise - 비동기 코드 작성하기

모든 언어가 마찬가지겠지만, 기존의 JavaScript에서는 비동기적 코드를 작성하고 관리하는 것은 크게 어려운 일이었다. node.js 에서는 콜백 을 이용하는 방식을 사용했지만, 이는 콜백 헬 이라는 새로운 문제를 만들어냈다. 이를 해결하기 위해 step 이나 async 같은 다양한 라이브러리가 나왔지만 이런 라이브러리로도 콜백 방식이 가지는 복잡도는 해결하지 못했고, 여전히 비동기 코드를 작성하는 것은 어려운 문제였다. 그래서 ECMAScript 6에서는 비동기 코드를 쉽게 작성할 수 있도록 Promise 를 표준 라이브러리에 도입하였다. Promise 는 그 이름에서도 알 수 있듯이 비동기적인 코드를 작성할 수 있도록 도와주는 promise monad 의 일종이다. Promise 는 기본적으로 생성자를 통해서 만들어진다. 이렇게 생성된 Promise 는 pending state가 된다. pending state는 아무 값도 가지지 않은 상태다. pending인 Promise 는 후에 resolved state (혹은 fulfill state) 가 되거나 rejected state가 될 수 있지만, 이 상태로는 아무것도 할 수 없다. Promise 의 상태를 바꾸기 위해서는 콜백 함수를 이용해야 한다. Promise 의 생성자는 한 개의 콜백 함수를 받는다. 이 콜백은 executor 라고 불리는데, Promise 객체를 생성하는 중에 호출된다. executor 가 호출될 때는 2개의 함수가 인자로 넘어간다. 첫 번째는 resolver 라고 불리고, 두 번째는 rejecter 라고 불린다. pending state인 Promise 의 resolver 가 호출되면 이 Promise 는 resolved state가 되고, resolver 의 인자를 값으로 지닌다. 반대로 pending state인 Promise 의 rejecter 이 호출되었다면 이 Promise 는 rejected state가 되고, rejecter 의 인자를 Promis

[Monad] 사용 예제 - Promise : 비동기 코드 작성하기

이미지
프로그래밍할 때 가장 어렵고 복잡한 일 중 하나가 비동기적인 코드를 안전하고, 읽기 쉽게 작성하는 것이다. Promise 는 이에 대해서 간단한 해결책을 제시한다. Promise 는 코드가 성공적으로 실행되었을 때의 값을 가지고 있거나, 코드가 실패했을 때 실패한 이유를 가지고 있다. 그래서 보통 Promise[T, E] 로 표현된다. 이는 기본적으로 Try 와 비슷하다. Try 와 차이는 Promise 는 그 객체가 생성되었을 때, 아직 연산이 끝났는지 알 수 없다. 코드가 비동기적으로 실행되기 때문이다. 코드가 비동기적으로 실행되기 때문에 Promise 에 bind operator를 통해서 타입을 진행시키는 일은 기본적으로 일을 예약하는 것이다. 이 일은 Promise 가 완료된 뒤 언젠가는 실행이 되지만, 언제 실행될지는 모른다. 이미 완료된 Promise 에 bind 한 콜백 함수가 언제 실행되는지도 모른다. 물론 실질적으로는 구현체에 따라서 언제 콜백 함수가 실행되는지 결정되어 있지만, 언제 실행될지 모른다고 생각하고 사용하는 것이 좋다. 아니 옳다. Promise 는 Option , Try 와 함께 가장 널리 쓰이는 모나드이다. 하지만 다른 두 모나드와는 다르게 구현체마다 인터페이스나 사용법이 다르고 그 특성도 다르다. 코드를 비동기적으로 실행시키는 것은 사용하는 언어나 플랫폼에 크게 의존하기 때문이다. 하지만 Promise 가 아직 완료되었는지 알 수 없는 일을 한 번 감싼 타입이라는 것만 잊지 않으면, 어떤 구현체라도 어떻게 사용해야 하는지 쉽게 이해할 수 있다. 어떤 경우에는 Future 라고 불리기도 하는데, 기본적으로 이 둘은 같은 일을 하기 위한 것이니 Promise에 대해서만 이해해도 딱히 문제없다. 굳이 차이를 두자면 Future 는 이미 생성된 모나드를 완료시키지 못하는 read-only Promise 라는 정도의 차이가 있을 뿐이다.

[ECMAScript 6] Symbol - 7번째 primitive type

지금까지 자바스크립트에는 number , boolean , string , null , undefined , object 의 6가지 타입밖에 없었다. 그래서 C의 enum 같은 타입이 필요하거나, 일종의 태깅 같은 것을 위해 고유한 값이 필요했을 경우 보통 number 나 string 타입을 이용했다. 하지만 ECMAScript 6에서는 이제 number 나 string 을 이용할 필요가 없다. ECMAScript 6에서는 새로운 타입인 Symbol 타입 이 추가되었기 때문이다. Symbol 타입의 값은 Symbol 함수를 통해서만 생성할 수 있고, 생성자를 통해서 만들 수 없다. Symbol 함수는 인자로 description을 받을 수도 있고, 아무 인자도 받지 않을 수도 있다. 이 인자는 실제로 생성되는 Symbol 에 영향을 주지 않는다. 로깅 등을 위해서 toString 함수를 이용해 string으로 변환할 때, 반영되지만 이는 디버깅을 위해서고, 일반적으로 이 description을 이용할 일은 없다. 같은 description을 이용해 생성한 Symbol 도 실제로는 다른 값을 가진다. 이는 Symbol 타입이 unique함을 보장하기 때문이다. Symbol 타입은 immutability와 unique 함이 보장된다. number 나 string 도 immutability는 보장된다. 하지만 unique 함은 보장되지 않는다. 이것이 Symbol 타입과 number / string 타입과의 차이점이다. 같은 Symbol 을 가지고 오기 위해서는 생성한 Symbol 을 전역 변수로 등록시키고 있어야 한다. 이것을 해주는 게 for 함수이다. Symbol.for() 함수는 key를 인자로 받는다. 이전에 같은 key로 생성한 Symbol 이 있으면 그 Symbol 을 돌려주고, 처음 받은 key면 새로운 Symbol 을 생성하여, 저장한 뒤 돌려준다. 주의해야 할 것은 Symbol.for(key) 함수는

[ECMAScript 6] block 안에서 함수 만들기

JavaScript 함수 선언의 가장 큰 특징은 함수의 선언 위치에 상관없이 언제나 코드의 가장 위에서 함수를 선언한 것처럼 코드가 실행된다는 것이다. 따라서 아래 두 코드는 사실 같은 코드라고 봐도 된다. 이를 function hoisting 이라고 한다. 이 덕분에 함수 선언문보다 앞에서 함수를 사용할 수 있다. 하지만 함수 선언은 언제나 스코프의 가장 윗부분으로 hoisting 된다. 따라서 함수 안에서 선언된 함수는 함수 내에서 언제나 같은 함수를 의미했고, 특정 block 안에서는 다른 함수를 의미하도록 사용할 수 없었다. 하지만 ECMAScript 6에서는 block 단위의 함수 선언을 허용한다. 즉, 위와 같이 if block 안에서만 다른 값을 의미하도록 하는 것이 가능하다. 하지만 아쉽게도 이는 아직 대부분 브라우저나 node.js에서는 구현되지 않았다 . 따라서 블록 단위 함수 선언을 사용하려면 babel.js 를 사용해야 한다.

[ECMAScript 6] 함수 이름 가져오기

자바스크립트는 두 가지 방식으로 함수를 선언할 수 있다. 평범하게 방법은 함수를 선언하여 사용할 수도 있고, 익명함수를 만들어 사용할 수도 있다. ECMAScript 5 까지는 어떻게 만들어지든 둘 사이에는 차이가 없었다. 만들 수 있는 위치나, 함수의 선언 및 할당이 실제로 이뤄지는 위치가 다르기는 하지만, 어쨌든 만들어지고 난 다음에 둘은 아무런 차이가 없었다. 위와 같은 코드는 사실 아래와 같은 코드에 syntax sugar일 뿐이다. 하지만 ECMAScript 6 이후로 둘은 name property라는 다른 점을 가진다. 첫 번째 방식으로 만든 함수는 named function이라고 불리며 name 이라는 프로퍼티를 가진다. 반면에 두 번째 방식으로 만들어진 함수는 anonymous function이라고 불리며 길이가 0인 문자열( "" )을 name property로 가진다.

[ECMAScript 6] fat arrow function

fat arrow function( => )는 ECMAScript 6 에 추가된 익명 함수를 생성하는 새로운 방법이다. 기존의 함수를 만드는 것보다 짧게 함수를 만들 수 있다. 이는 다른 함수에 콜백으로 함수를 넘겨야 하는 경우 요긴하게 사용된다. 하지만 단순히 길이가 짧다는 것만이 arrow function의 장점이 아니다. 오히려 중요한 특색은 arrow function은 this 를 lexical scope 에서 찾는다는 것이다. JavaScript 함수의 가장 큰 특징 중 하나는 this가 dynamic binding 된다는 것이다. 보통은 큰 문제가 되지 않지만, 메소드를 콜백으로 넘겨주어야 하는 경우나 메소드를 변수로 받을 경우 원하는 대로 돌아가지 않았다. ECMAScript 5 에서는 Function에 bind 메소드 가 추가되어 원하는 오브젝트를 this 로 바인드 한 함수를 만들 수 있지만, 매번 이런 작업을 하는 것은 귀찮은 일이다. 이제 ECMAScript 6에서는 이런 경우에 => 을 이용하여 this 가 lexical binding 된 함수를 만들면 된다.

[TypeScript] Type guard - sum type 분리하기

Type guard는 다른 언어에서 보기 힘든 TypeScript만의 독특한 기능으로, 타입 인트로스펙션 을 통해 분기한 블록 안에서 해당 변수의 타입을 한정시켜주는 기능을 말한다. TypeScript를 사용하다 보면, 하나의 변수가 2개 이상의 타입일 가능성이 있는 경우가 자주 생긴다. TypeScript의 본질이 JavaScript이고 이는 동적 타입 언어이기 때문일 것이다. 이를 위해서 TypeScritp는 any 타입을 이용하거나, 조금 더 안전한 사용을 위해서 유니언 타입을 이용한다. 하지만 유니언 타입의 값은 그 값이 될 수 있는 모든 타입이 공통으로 가지는 함수와 프로퍼티만 이용할 수 있고, 모든 타입이 들어갈 수 있는 함수에만 사용 사용할 수 있다. 이런 불편함을 없애기 위해서 나온 기능이 type guard이다. 위의 코드처럼 여러 개의 타입이 될 수 있는 값을 사용하기 전에 인트로스펙션을 이용해서 타입을 확인하고 값을 사용하는 것은 JavaScript에서 볼 수 있는 흔한 패턴이다. 이렇게 타입을 확인하고 나면, 확인한 블록 안에서 그 값은 해당하는 타입이 되는 것이 type guard이다. 하지만 아직 모든 인트로스펙션에 대해서 type guard가 적용되는 것은 아니다. 현재 type guard가 적용되는 경우는 인트로스펙션이 조건문에 들어가는 if 블록과 그에 따라오는 else 블록뿐이다. 위의 예제처럼 if 블록이 반드시 return 하여 그다음은 else 블록과 다를 바 없는 경우에는 type guard가 적용되지 않는다. 게다가 모든 인트로스펙션이 가능한 것도 아니고, instanceof 를 사용하는 경우와 typeof 의 결과가 'number' , 'string' , 'boolean' 이 되는 경우뿐이다. 그래서 underscore 등을 이용해서 타입 체킹을 하는 경우나 인트로스펙션 부분을 함수로 뺀 경우는 type guard가 동작하지 않는다. 이는 TypeS

이 블로그의 인기 게시물

[C++] enum class - 안전하고 쓰기 쉬운 enum

Log Aggregator 비교 - Scribe, Flume, Fluentd, logstash

RAII는 무엇인가

[Python] cache 데코레이터로 최적화하기

[Web] SpeechSynthesis - TTS API