라벨이 promise인 게시물 표시

[TypeScript] Promise.all에는 인자 개수 제한이 없다

트위터에서 이상한 글을 봤다. TypeScript 가 선언한 Promise.all 이 iterable 을 받지 않고 인자 개수 제한이 있다는 것이다. 근데 그럴 리가. TypeScript쯤 되는 프로젝트에서 무언가가 스펙과 다른 것으로 보인다면, 코드를 잘못 이해했을 확률이 높다. 코드를 다시 확인해보자. 당연히 iterable 을 인자로 받는 Promise.all 선언 도 있다. 다만, 이 선언이 es2015.promise.d.ts 가 아닌 es2015.iterable.d.ts 에 있을 뿐이다. 타입스크립트 컴파일러 옵션 중 --lib 으로 사용할 라이브러리를 지정할 수 있다. 대부분 es2015 , es2018 같은 식으로 버전을 지정하여 포함하는 것이 일반적이라 잘 알려지지 않았지만, es2015.symbol 로 Symbol 에 대한 선언만 포함하거나, es2015.promise 로 Promise 에 대한 선언만 포함하는 것이 가능하다. 각 라이브러리는 서로 간에 의존성이 없도록 작성돼 있으며, 특히 iterable 에 관련된 선언은 전부 es2015.iterable 에서 선언한다. 예를 들어 Map 이나 Set 은 es2015.collection 에 선언돼 있지만, iterable 을 반환하는 entries , values , keys 등의 선언은 전부 es2015.iterable 에 선언돼 있다. 마찬가지로 iterable 을 인자로 받는 Promise.all 함수도 es2015.iterable에 선언돼있다. iterable 을 받는 Promise.all 함수 선언은 es2015.iterable 에 선언돼 있는데, es2015.promise 에 10개가 더 선언돼있다. 이들은 무엇일까? 사실 이 함수들은 배열을 인자로 받는 함수가 아니라 tuple 을 인자로 받는 함수 선언이다. JavaScript 에는 임의 개수의 원소를 가지는 배열은 있지만, 고정된 개수의 원소를 가지는 tuple은 없다. 그래서 tuple이 필요할 때 배열을 사...

[ECMAScript6] 성공적인 Promise는 중첩되지 않는다.

ES6 Promise 에는 독특한 특징이 있는데, 지난번 글 에서는 설명할 타이밍을 잡지 못해서 그냥 넘어갔었다. 이번에 그 특징에 관해 설명하도록 하겠다. 전에 모나드에 관해서 설명 하면서 모나드의 가장 기본적인 operator 중 하나인 bind operator 는 M[T] 타입의 모나드가 T 타입의 인자를 받아서 M[U] 타입의 값을 리턴하는 함수를 인자로 받아서 M[U] 타입의 모나드로 타입을 진행시킨다 1) 고 하였다. 하지만 ES6 Promise 의 then 함수 에 관해서 설명하면서 then 함수가 받는 콜백이 값을 리턴하면 resolved 된 Promise 가 리턴되고, 값을 throw 하면 rejected 된 Promise 가 리턴된다고 하였다. 즉, then 함수만으로는 모나드를 리턴하는 함수를 통해서 타입을 전진시키는 bind operator를 구현할 수 없으므로 완전한 모나드를 구현하지 못한다. 그렇다면 ES6의 Promise 는 어떻게 Promise 를 전진시킬까? 간단하다. 그냥 then 함수가 인자로 받는 콜백은 Promise 를 리턴해도 된다. 사실 Promise 가 모나드라는 것을 생각하면, 이쪽이 올바른 사용 법이다. 하지만 ES6뿐 아니라 다른 모나드 구현체에서도 bind operator뿐 아니라, 모나드가 아닌 값을 리턴하는 함수. 즉, (M[T], T => U) => M[U] 에 해당하는 함수도 구현한다. 이는 사실 내부적으로 unit operator 와 bind operator를 호출하기 때문에 굳이 필요한 함수는 아니다. 그러함에도 이 함수가 존재하는 이유는 실제로 이 구현을 사용하는 경우가 일반적인 bind operator를 사용하는 경우보다 많아서 사용자의 편의를 위해서 제공되는 것일 뿐이다. 그래도 보통은 둘을 같은 이름의 함수로 구현하지는 않고, 다른 이름의 함수로 구현한다. ES6에서는 then 함수가 두 가지 일을 한다. 동적 타입 언어의 특징을 최대한 활용한 것이다...

[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 라는 정도의 차이가 있을 뿐이다.

이 블로그의 인기 게시물

USB 2.0 케이블의 내부 구조

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

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

[Web] SpeechSynthesis - TTS API

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