46 제너레이터와 async/await
제너레이터란?
ES6에 도입됨
코드 블록 실행을 일시중지했다가 필요한 시점에 재개할 수 있는 특수한 함수
일반함수와의 차이
- 함수호출자에게 함수 실행 제어권을 양도할 수 있음함수를 부른 함수는 함수 실행을 제어할 수 없다.함수 호출자가 일시중지, 재개가 가능하다는 것
- 제너레이터 함수는 함수 실행을 함수 호출자가 제어할 수 있다.
- 일반함수를 호출하면 제어권은 해당 함수에게 넘어간다.
- 제너레이터 함수는 함수 호출자와 함수 상태를 주고받을 수 있다.
- 제너레이터 함수를 호출하면 제네레이터 객체를 반환한다.
- 제네레이터 함수를 호출하면 함수 코드를 실행하는게 아니라 이터러블이면서 동시에 이터레이터인 제너레이터 객체를 반환함
제너레이터 함수의 정의
function*로 선언하며, 하나 이상의 yield표현식을 사용함
function *generator(){
yield 1;
}
제너레이터 객체
이터러블이면서 동시에 이터레이터임
function *generator(){
yield 1;
yield 2;
yield 3;
}
const gene=getnerator();
제너레이터 객체는 next 메서드를 갖는 이터레이터이지만, 이터레이터에는 없는 return, throw 메서드를 가진다.
- next 메서드를 호출하면 yield표현식까지 코드블록을 실행하고, yield된 값을 value 프로퍼티 값으로, false를 done프로퍼티값으로 갖는 이터레이터 리절트 객체를 반환한다.
- return 메서드를 호출하면 인수로 전달받은 값을 value 프로퍼티 값으로, true를 done프로퍼티 값으로 갖는 이터레이터 리절트 객체를 반환한다.
- throw메서드를 호출하면 인수로 전달받은 에러를 발생시키고, undefined를 value로, done을 true로 갖는 이터레이터 리절트 객체를 반환함
제너레이터 일시중지와 재개
제너레이터 객체는 next를 통해 해당 함수의 다음 yield까지를 수행한다.
yield가 더이상 없다면 함수의 반환값을 value로하고, true를 done으로 갖는 객체를 리턴한다.
next
제너레이터 객체의 next메서드에는 인수를 전달할 수 있다.
다만, 첫 next의 인수로는 전달할 수 없다.
function *generator(){
const x =yield 1;
const y=yield(x+10);
return x+y;
}
첫 x에 yield 1이 할당되지 않는다.
x는 이후 next의 인수로 결정된다.
제너레이터로 피보나치 수열 구현하기
const infiniteFibo=(function*(){
let [pre, cur]=[0,1];
while(true){
[pre,cur]=[cur,cur+pre];
yield cur;
}
}());
for (const num of infiniteFibo){
if(num>10000) break;
console.log(num);
}
비동기 처리
next 메서드와 yield를 통해 비동기를 동기처럼 구현 가능하다.
const fetch=require('어쩌구~');
const async=callback=>{
const generator=callback();
const onResolved=arg=>{
const result=generator.next(arg);
return result.done? result.value: result.value.then(res=>onResolved(res));
}
}
(async (function* fetch(){
const response=yield fetch();
const todo=yield response.json();
console.log(todo);
}());
async/await
비동기 코드를 동기처리 할수 있게 함
async
await 키워드는 반드시 async 함수 내부에서 사용해야함
async 함수는 언제나 프로미스를 반환함
프로미스를 반환하지 않아도, 프로미스로 변환해서 반환함
constructor에는 사용 불가능하다
await
await는 프로미스가 settled(수행된 상태)가 될때까지 기다렸다가 프로미스가 resolve한 결과를 반환한다.
반드시 프로미스 앞에서 사용해야한다.
여러개를 사용할 때는 주의해야한다.
async function foo(){
const a= await new Promise(resolve=>setTimtout(()=>resolve(1),1000);
const b= await new Promise(resolve=>setTimtout(()=>resolve(2),2000);
const c= await new Promise(resolve=>setTimtout(()=>resolve(3),3000);
console.log(a,b,c)
}
foo(); //약 6초
이렇게 사용하기보다는 Promise.all을 사용하자.
async function foo(){
const res=await Promise.all([
new Promise(resolve=>setTimtout(()=>resolve(1),1000),
new Promise(resolve=>setTimtout(()=>resolve(2),2000),
new Promise(resolve=>setTimtout(()=>resolve(3),3000)]);
console.log(res);
}
foo(); //약 3초
try, catch
async/await 에서 에러처리로 try…catch문을 사용가능함
async함수 내에서 사용해야하며, catch하지 않으면 reject하는 프로미스를 반환함