Programming Languages

[TypeScript] Promise / async & await

Sara.H 2020. 11. 16. 18:08

 

 

TypeScript compiling 참고

code.visualstudio.com/docs/typescript/typescript-compiling

 

File 을 로컬에서 읽어들이기

기본적으로 fs 패키지의 readFile 함수를 사용/ 동기로 처리하고 싶은 경우 readFileSync 함수를 사용하면 된다.

import {readFileSync, readFile} from 'fs'; 

const buffer : Buffer = readFileSync('../package.json'); 

//promise 를 사용한 예시 
const readFilePromise = (filename : string) : Promise<string> => 
    new Promise<string>(
        (resolve, reject) => {
            readFile(filename, (error : (NodeJS.ErrnoException | null), buffer : Buffer) => {
                if(error){
                    //error 를 리젝트 함수로 전달한다. 
                    reject(error); 
                }else{
                    resolve(buffer.toString())
                }
            })
        }
    ); 

(
    async() => {
        const content = await readFilePromise('../package.json'); 
        console.log('read package.json using Promise and async'); 
        console.log(content); 
    }
)() 

참고

* Promise 객체에 리턴 타입을 지정해 주어야 한다. 위에서는 텍스트 파일을 읽어들이므로, string 으로 지정함.

* Promise 의 생성자에는 (resolve, reject) 라는 함수 포인터를 인자로 가진 함수가 매개변수로 전달된다.

* 작업이 성공하는 경우 resolve 함수로 결과가 전달, 작업이 실패하는 경우 reject 함수로 결과가 전달되는 방식

* 책에서는 error 타입을 Error 로 지정했던데, 그렇게 하면 에러가 남. NodeJS.ErrnoException | null 이라는 유니언 타입으로 지정해 주어야 에러가 나지 않았음.

 

 

단일 스레드로 동작하는 자바스크립트.

자바스크립트 코드는 항상 한 개의 작업 스레드에서 실행된다.

웹 브라우저나 Nodejs 프로그램 자체는 다중스레드로 동작하나, js 코드는 한 개의 작업 스레드, 즉 단일 스레드에서 동작함.

 

타입스크립트 혹은 자바스크립트는 단일 스레드에서 동작하므로, 코드를 작성할 때 항상 비동기 방식으로 동작하는 API 를 사용해 프로그램의 반응성을 훼손하지 말아야 한다.

 

 

Promise

* ES5 에서 정식 기능으로 채택됨.

* Promise 란 이름의 클래스, new 연산자를 통해 객체를 생성.

 

```

const promise = new Promise(콜백함수)

```

new Promise<T>((resolve : (successValue : T) => void, reject : (any) => void) => {
	//1. 작업 시작 
    //2. 작업 결과를 resolve, reject 로 넘겨주기 
})

 

Promise 함수를 사용하는 쪽에서는 ...

import {readFilePromise} from './readFilePromise'; 

readFilePromise('../package.json')
.then
(
    (content : string) => {
        console.log('readin package.json file ... ')
        console.log(content); 
        return readFilePromise('../tsconfig.json'); 
    }
).then(
    (content : string) => {
        console.log('reading again ... \n'); 
        console.log(content);
        //의도적으로 에러를 반환해본다. 
        return readFilePromise('.'); 
    }
)
.catch((err : Error ) => {
    console.log(`Error ${err}`)
})
.finally(
    () => console.log("프로그램 종료염!")
)

Promise 는 resolve, reject 라는 정적 메서드를 제공함.

Promise.resolve(값) 을 호출하면 항상 이 '값' 은 then 메서드 안에서 얻을 수 있다.

Promise.reject(Error 타입 객체)를 호출하면 이 Error 타입 객체는 항상 catch 메서드의 콜백 함수에서 얻을 수 있다.

 

 

Promise.all 메서드

const getAllResolvedResult = <T>(promises : Promise<T>[]) => Promise.all(promises);
//resolve 된 것들의 값을 반환한다. 
//에러가 있으면 바로 catch 에서 뱉어내고 종료됨. 

getAllResolvedResult<any>(
    [Promise.resolve(true), 
    Promise.resolve('hello')]
).then(
    result => 
    console.log(result)
)

getAllResolvedResult<any>(
    [Promise.reject(new Error('error')), 
    Promise.resolve(1)]
).then(
    result => console.log(result)
).catch(
    error => console.log(`Error : ${error}`)
)

 

Promise.race 메서드

Promise.race(
    [
        Promise.resolve(true), 
        Promise.resolve('hello')
    ]
).then(
    val => 
    console.log(val)
)

Promise.race(
    [
        Promise.resolve(new Error('this is an error')), 
        Promise.resolve('hello')
    ]
).then(
    val => 
    console.log(val)
).catch(
    err => 
    console.log(err)
)

* 가장 먼저 resolve 된 값을 반환하고 종료한다.

* 에러가 먼저 걸리면 에러를 던지고 종료한다.

 


async / await

* 2013년 MS 에서 C#5.0 을 발표, 비동기 프로그래밍 코드를 간결하게 구현할 수 있는 async 와 await 구분을 제공

* 이후 자바스크립트를 포함하여 많은 프로그래밍 언어가 이를 차용함.

 

async 이름의 function modifier 가 있는 함수 바디에서만 await 키워드를 사용할 수 있음

const test = async() => {
	await Promise객체 혹은 값
}

async function test2() {
	await Promise객체 혹은 값
}

* async 는 함수이므로 일반 함수처럼 호출 가능함.

* 일반 함수처럼 사용할 수 있으면서도, Promise 객체로서도 사용이 가능함.

 

//위에서 작성한 test 함수 
test()
.then(
	() => test2() 
)

test 함수가 resolve 된 후에 test2 를 호출하는 것.

 

에러 처리

* async 함수로 에러 처리를 할 때는 Promise.reject() 함수 안에다가 에러 객체를 넣어주는 식으로 처리할 수 도 있고,

* async 함수 안에서 throw new Error() 와 같이 한 후에, async함수().catch( err => console.log(err)) 와 같이 받아서 처리할수도 있다.

const awaitReject = async() => {
	await Promise.reject(new Error('this is an error'))
}

awaitReject() //비정상 종료

awaitReject()
.catch(
	err => console.log(err.message)
)

 

 

 

* image source : ko.m.wikipedia.org/wiki/%ED%8C%8C%EC%9D%BC:Typescript_logo_2020.svg