타입스크립트 기초 - 12

Stulta Amiko·2022년 7월 6일
0

타입스크립트 기초

목록 보기
12/24
post-thumbnail

Promise

import { readFileSync,readFile } from "fs";

console.log('read package.json using synchronous api')
const buffer: Buffer = readFileSync('./package.json')
console.log(buffer.toString())

readFile('./package.json',(err: Error,buffer: Buffer)=>{
    console.log('read package.json using asynchronous api')
    console.log(buffer.toString())
})

const readFilePromise = (filename: string): Promise<string> => 
    new Promise<string>((resolve,reject)=>{
        readFile(filename,(err: Error,buffer: Buffer) => {
            if(err)
                reject(err)
            else 
                resolve(buffer.toString())
        })
    });

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

package.json의 내용을 가져오는 코드를 만들어 봤다.
순서대로 동기/비동기/프로미스를 이용해석 가져오는 코드이다.
운영체제가 제공하는 서비스를 API라고 한다.

파일내용을 모두 읽을때까지 동작을 멈추는 방식을 동기식
동작을 멈추지 않는대신 결과를 콜백으로 얻게하는게 비동기식이라고 한다.

비동기 콜백함수는 API의 물리적인 동작 결과를 수신하는 목적으로 사용된다.

readFileSync를 이용하면 파일 읽기를 할 수 있다.
Buffer를 반환하고 그안에 값을 toString()을 해주면 내부값을 볼 수 있는데
readFileSync가 작동하는 동안 잠시동안 멈추게 된다.
이는 동기적으로 작동한다는 것을 뜻한다.

readFile을 이용하면 비동기식으로 사용할 수 있는데
읽은 결과는 콜백으로 전달된다.

readFile('./package.json',(err: Error,buffer: Buffer)=>{
    console.log('read package.json using asynchronous api')
    console.log(buffer.toString())
})

위에서 구현한것에서 비동기적으로 작동하는 readFile 메서드를 가져오면 이런방식으로 작동한다.
내부 인자로 콜백을 주는데 그중 buffer에 값이 저장되는것이고 오류가 나면 err에 저장이 되는것이다.

readFile을 이용하면 비동기식으로 사용할 수 있는데
읽은 결과는 콜백으로 전달된다.

자바스크립트는 싱글 스레드로 동작하므로 왠만해선 readFileSync와 같은 동기메서드의 사용을 자제해야한다.
이렇게 짧은 코드의 경우 실행이 짧아서 빨리 끝나게 되지만 만약 코드가 더 길어지게 된다면 이는 프로그램이 지연되게 되면서 좋지않은 결과를 낳게 될것이다.

하지만 이렇게 비동기방식 API를 많이 사용하다보면 콜백지옥에 빠지게 된다.
이를 개선하기 위해 나온방식이

Promise

프로미스는 클래스여서 사용하려면 new 연산자를 이용해서 프로미스 객체를 만들어야한다.

const readFilePromise = (filename: string): Promise<string> => 
    new Promise<string>((resolve,reject)=>{
        readFile(filename,(err: Error,buffer: Buffer) => {
            if(err)
                reject(err)
            else 
                resolve(buffer.toString())
        })
    });

위와같은 방식으로 구현할 수 있다.

사용하는 방식을 보면 제네릭 클래스 형태로 사용을 하고있다.

readFilePromise('./package.json')
    .then((content: string)=>{
        console.log(content)
        return readFilePromise('./tsconfig.json')
    })
    .then((content: string)=>{
        console.log(content)
        return readFilePromise('.')
    })
    .catch((err: Error)=>console.log('err:',err.message))
    .finally(()=>'end')

원래는 이런식으로 이용을 하는데
tsconfig가 출력이 안되는 문제가 생겼다.
코드자체의 문제는 아닌것 같고 tsconfig를 불러오지 못하는 문제같았다.
여튼 그걸 불러오는게 중요한건 아니라고 생각하기 때문에 넘어가겠다.

then 메서드는 resolve에서 나온값을 보여준다.
catch 메서드는 reject에서 거절당한 값을 보여준다.
책에서 나오는 promise의 메서드는 예전에 자바스크립트 복습에서 한번 다뤘던 내용의 메서드들이 나오기는 한다.

모든 내용이 같아야하는 all메서드라던지
하나라도 참이면 뒤에있는 메서드는 실행시키지 않는 race 메서드도 있다.

async / await

const test = async() =>{
    const value = await Promise.resolve(1)
    console.log(value)
}

test()

await 키워드는 피연산자의 값을 반환해 준다.
피연산자가 Promise 객체이면 then 메서드를 호출해서 얻은 값을 반환해 준다.

await 키워드는 async라는 이름의 함수수정자 내부에서만 사용할 수 있다.

const test1 = async() =>{
    let value = await 1
    console.log(value)
    value = await Promise.resolve(1)
    console.log(value)
}

const test2 = async() =>{
    let value = await 'hello'
    console.log(value)
    value = await Promise.resolve('hello')
    console.log(value)
}

test1()
test2()

실행결과
1
hello
1
hello

실행결과가 좀 특이한데 두함수가 동시에 실행된거서럼 보인다.

const test1 = async() =>{
    let value = await 1
    console.log(value)
    value = await Promise.resolve(1)
    console.log(value)
}

const test2 = async() =>{
    let value = await 'hello'
    console.log(value)
    value = await Promise.resolve('hello')
    console.log(value)
}

test1().then(()=>test2())

실행결과
1
1
hello
hello

이런식으로 하면 의도한 대로 나온다.
test1함수를 전부 resolve한후에 test2함수를 실행하기 때문이다.

async함수는 값을 반환하는 함수이다.
Promise 형태로 변환되므로 then 메서드를 호출해서 얻어야한다.

import { readFile } from "fs";

const readFilePromise = (filename: string): Promise<string> => 
    new Promise<string>((resolve,reject)=>{
        readFile(filename,(err: Error,buffer: Buffer) => {
            if(err)
                reject(err)
            else 
                resolve(buffer.toString())
        })
});


const readFilesAll = async (filenames: string[]) => {
    return await Promise.all(
        filenames.map(filename => readFilePromise(filename))
    )
}

readFilesAll(['./package.json','/Users/user/Desktop/programming/web/nodepractice/syntax/typescript/ch07-1/tsconfig.json'])
    .then(([packageJson,tsconfigJson]: string[])=>{
        console.log('<package.json>: ',packageJson)
        console.log('<tsconfig.json>: ',tsconfigJson)
    })
    .catch(err=>

readFile을 프로미스로 만든 readFilePromise를 이용해서 readFilesAll 을 구현한 모습이다.
실행결과는 tsconfig.json과 package.json이 제대로 나오는 모습을 볼 수 있다.

0개의 댓글