[S2U3] JS/Node 비동기

👽·2024년 3월 8일
0
post-thumbnail

CH1. 비동기

📌동기(synchronous) & 비동기(asynchronous)

🔸 동기 : 특정 코드의 실행이 완료될 때까지 기다리고 난 후 다음 코드를 수행하는 것.

🔸 비동기 : 특정 코드의 실행이 완료될 때까지 기다리지 않고 다음 코드들을 수행하는 것. 동기적으로 운영하는 경우보다 훨씬 효율적.

🔸 JavaScript의 작동원리 : 싱글 스레드 기반으로 동작하는 언어 (한번에 한 가지 동작만 처리할 수 있음), 따라서 동기적으로 작동. JavaScript가 작동하는 환경(런타임)에서 비동기 처리를 도와주기 때문에 특별한 작업 없이 비동기 처리를 할 수 있음.

📌비동기 JavaScript

setTimeout(callback, millisecond)

🔸 일정 시간(millisecond) 후에 함수(callback)를 실행
🔸 return : timeoutID. 생성된 타이머를 식별할 때 사용.

clearTimeout(timerId)

🔸 timerId를 입력받아 setTimeout() 타이머를 종료
🔸 return : 없음

setInterval(callback, millisecond)

🔸 일정 시간(millisecond)의 간격을 가지고 함수(callback)를 반복적으로 실행
🔸 return : timeoutID

clearInterval(timerId)

🔸 timerId를 입력받아 setInterval() 타이머를 종료
🔸 return : 없음

📌 비동기 Callback

🔸 비동기 작업은 언제 끝날지 모른다는 특징을 가지며, 코드의 실행순서가 뒤죽박죽이 될 수 있음.
🔸 예를 들어, 네트워크 통신 같은 비동기 작업이 완료되고 나서, 받아온 데이터를 처리하는 코드가 수행되도록 해야한다면, 즉 특정 비동기 코드가 끝나고 나서 후처리를 하고 싶으면 Callback 함수를 이용해 비동기 코드를 동기화 시키면 됨.
🔸 이런 Callback 함수를 비동기 Callback이라고 부름.

// 1. 로그인
function login(username, callback) {
    setTimeout(() => {
        callback(username)
    }, 1000)
}
// 2. 장바구니에 넣기
function addToCart(product, callback) {
    setTimeout(() => {
        callback(product)
    }, 1000)
}
// 3. 함수 실행 시, 1초 후 로그인 함수가 실행되고 그다음 1초뒤에 장바구니 함수가 실행됨
login('탁구', (username) => {
    console.log(`${username}님 안녕하세요`)
    addToCart('사료', (product) => {
        console.log(`${product}를 장바구니에 넣었습니다`)
    })
})

Callback Hell

🔸 비동기 코드의 순서를 제어할 수 있지만 코드가 길어질수록 복잡해지고 가독성이 낮아지는 Callback Hell이 발생함.

const printString = (string, callback) => {
  setTimeout(function () {
    console.log(string);
    callback();
  }, Math.floor(Math.random() * 100) + 1);
};
const printAll = () => {
  printString('A', () => {
    printString('B', () => {
      printString('C', () => {
        printString('D', () => {
          printString('E', () => {
            printString('F', () => {
              printString('G', () => {
                printString('H', () => {
                  printString('I', () => {
                    printString('J', () => {
                      printString('K', () => {
                        printString('L', () => {
                          printString('M', () => {
                            printString('N', () => {
                              printString('O', () => {
                                printString('P', () => {});
                              });
                            });
                          });
                        });
                      });
                    });
                  });
                });
              });
            });
          });
        });
      });
    });
  });
};
printAll();
console.log(
);

🔸 Callback Hell의 현상을 방지하기 위해 Promise가 사용되기 시작

📌 Promise

🔸 비동기 처리에 사용되는 자바스크립트 객체로 비동기 작업이 맞이할 성공 혹은 실패를 나타냄

🔸 대기(pending) : 이행하지도, 거부하지도 않은 초기 상태. undefined
🔸 이행(fulfilled) : 연산이 성공적으로 완료됨. 결과값
🔸 거부(rejected) : 연산이 실패함. Error

new Promise. 프로미스 생성하기

🔸 PromiseClass이기 때문에 new 키워드를 통해 Promise 객체를 생성

const promise = new Promise()

🔸 또한 Promise는 비동기 처리를 수행할 콜백 함수(executor)를 인수로 전달받는데 이 콜백 함수는 resolve, reject 함수를 인수로 전달받음.

  • resolve(result) : 비동기 작업이 완료되면 결과 값을 처리할 함수. 성공적으로 이행되면 Promise 객체는 fullfilled 상태를 가짐.
  • reject(error) : 비동기 작업이 거부되면 에러처리 할 함수. rejected 상태를 가진 Promise 객체를 반환.
const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        const data = { name : '탁구'}
        if(data) { 
            console.log('네트워크 요청 성공')
            resolve(data)
        } else {
            console.log('네트워크 요청 실패')
            reject(new Error('네트워크 문제'))
        }
    }, 1000)
})

🔸 promise 객체가 생성되면, executor 함수가 즉시 실행되기 때문에, 이를 방지하기 위해서 특정 함수 안에 promise 객체를 생성해주면 됨.

function getDate() {
	const promise = new Promise() 
   // 위 코드와 동일
	return promise
}

.then()

🔸 Promisefullfilled 상태가 되면, .then 메서드가 실행되고, 콜백 함수를 호출. 콜백 함수는 Promise의 결과값을 매개변수로 전달 받을 수 있음

getData().then((data) => {
    const name = data.name
    console.log(`${name}님 안녕하세요`)
})
  • executor에 작성했던 코드들이 정상적으로 처리가 되었다면 resolve 함수를 호출하고, .then 메서드로 접근 가능.
  • .then 안에서 리턴한 값이 PromisePromise의 내부 프로퍼티 result를 다음 .then의 콜백 함수의 인자로 받아올 수 있음.
  • Promise가 아니라면 리턴한 값을 .then 의 콜백 함수의 인자로 받아올 수 있음.

.catch()

🔸 에러가 발생했을 경우, Promise 객체는 rejected 상태가 되고, .catch 메서드가 실행. 전달된 콜백 함수는 에러를 처리.

getData().then((data) => {
    const name = data.name
    console.log(`${name}님 안녕하세요`)
}).catch((error) => {
    //...
})

.finally()

🔸 Promise가 처리되고 성공 여부와 상관없이 지정된 콜백 함수가 실행됨.

Promise chaining

🔸 .then()은 항상 새로운 Promise 객체를 리턴하기 때문에 연속해서 .then 메서드를 사용할 수 있음. 이를 Promise chaining이라고 함
🔸 따라서 비동기 작업을 순차적으로 진행해야 하는 경우 사용.

const pormise = getData()
promise
	.then((data) => getData())
	.then((data) => getData())
 	// ...   
})

💡 .then 내에서 다른 값으로 리턴해줘도 .then은 항상 Promise를 리턴. 리턴된 다른 값은 곧바로 Promise로 감싸져서 resolve가 된 상태로 되고 다음 .then 메서드에 전달됨. 따라서 Promiseresolve될 때까지 기다릴 필요없이 즉시 사용할 수 있음.

Promise.all()

🔸 Promise.all(iterable) : 여러 개의 비동기 작업을 동시에 처리하고 싶을 때 사용.

🔸 인자로는 배열을 받아, 해당 배열에 있는 모든 Promise에서 executor 내 작성했던 코드들이 정상적으로 처리가 되었다면 결과를 배열에 저장해 새로운 Promise를 반환.

🔸 인자로 받는 배열에 있는 Promise 중 하나라도 에러가 발생하게 되면 나머지 Promise의 상태와 상관없이 즉시 종료.

Promise.allSettled()

🔸 Promise.allSettled(iterable) : 주어진 모든 Promise를 이행하거나 거부한 후, 각 Promise에 대한 결과를 나타내는 객체 배열을 반환.
🔸 성공 여부에 관련 없는 여러 비동기 작업을 수행해야 하거나, 항상 각 Promise의 실행결과를 알고 싶을 때 사용.

Promise.any()

🔸 Promise.any(iterable) : iterable 안에 있는 Promise 중에 가장 먼저 resolve가 된 Promise를 반환.
🔸 배열로 들어간 Promise가 모두 reject 되어야만 반환된 Promisereject 됨.

Promise.race()

🔸 Promise.race(iterable) : iterable 안에 있는 Promise 중에 가장 먼저 완료된 것의 결과값으로 그대로 이행하거나 거부.

📌 Async/Await

🔸 JavaScript는 ES8에서 async/await키워드를 제공. 이를 통해 복잡한 Promise 코드를 간결하게 작성 가능.
🔸 async : 함수 앞에 키워드를 작성. 항상 Promise를 반환하는 비동기 함수가 됨.

💡 async 함수 내에 Promise를 직접 리턴하면, Promise로 두번 감싸지는 것이 아니라, 그대로 Promise로 리턴됨.

🔸 await : async 함수 내에서 코드 앞에 await 키워드를 작성. await 키워드가 작성된 코드가 동작하고 나서야 다음 순서의 코드가 동작함.

// 함수 선언식
async function funcDeclarations() {
	await 작성하고자 하는 코드
	...
}

// 함수 표현식
const funcExpression = async function () {
	await 작성하고자 하는 코드
	...
}

// 화살표 함수
const ArrowFunc = async () => {
	await 작성하고자 하는 코드
	...
}
const printString = (string) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve();
      console.log(string);
    }, Math.floor(Math.random() * 100) + 1);
  });
};

const printAll = async () => {
  await printString('A');
  await printString('B');
  await printString('C');
};

printAll();

console.log(
  `Async/Await을 통해 Promise를 간결한 코드로 작성할 수 있게 되었습니다.`
);

에러 처리

🔸 try-catch : 에러가 날 수 있는 부분을 try 문 안에 작성하고, catch로 에러 처리.

async function getData() {
	let user
    try {
    	user = await getUser()
    } catch(err) {
    	// 에러처리
    }
}

CH2. Node.js

📌 Node.js 모듈 사용법

Node.js

🔸 비동기 이벤트 기반 JavaScript 런타임

Node.js 내장 모듈을 사용하는 방법

🔸 모듈 : 어떤 기능을 조립할 수 있는 형태로 만든 부분.

  • fs(File System) : PC의 파일을 읽거나(readFile) 저장하는(writeFile) 등의 일을 할 수 있게 도와줌.
  • DNS : 파일 시스템 모듈이 파일을 읽거나 저장하는 기능을 구현할 수 있도록 도움

🔸 모든 모듈은 '모듈을 사용하기 위해 불러오는 과정'이 필요. JavaScript 코드 가장 상단에 require 구문을 이용하여 다른 파일을 불러올 수 있음

const fs = require('fs'); // 파일 시스템 모듈을 불러옵니다
const dns = require('dns'); // DNS 모듈을 불러옵니다

// 이제 fs.readFile 메서드 등을 사용 가능

3rd-party 모듈을 사용하는 방법

🔸 서드 파티 모듈(3rd-party module) : 해당 프로그래밍 언어에서 공식적으로 제공하는 빌트인 모듈(built-in module)이 아닌 모든 외부 모듈
🔸 다운로드하기 위해서는 npm install 모듈명을 사용

// 1. 터미널에 npm install
npm install 모듈명
// 2. Node.js에서 require구문으로 불러옴
const 모듈명 = require('모듈명')

📌 Node.js 공식 문서 가이드

fs.readFile 메서드 사용하기

🔸 로컬에 존재하는 파일을 비동기적으로 읽어옴.
🔸 fs.readFile(path[, options], callback)

  • path (string | Buffer | URL | integer) : 파일 이름을 작성.
  • options (Object | string) : encoding, flag, signal을 필요에 따라 작성
  • callback : 파일을 읽은 뒤 콜백함수가 비동기적으로 실행됨

CH3. fetch API

📌 fetch를 이용한 네트워크 요청

🔸 fetch(URL) : Web API 중 하나로, 특정 URL로 네트워크 요청을 보내는 비동기 함수.
🔸 Promise를 리턴함
🔸 json() : 본문 텍스트를 JSON으로 입력받아 파싱하여 JavaSctipt 객체로 이행하는 Promise를 반환

fetch('https://jsonplaceholder.typicode.com/users')
    .then((response) => {
        return response.json()
    }).then((data) => {
        console.log(data)
})
// 📍 async-await
async function fetchData() {
    const response = await fetch('https://jsonplaceholder.typicode.com')
    const data = await response.json()
    console.log(data)
}
fetchData()
profile
코린이👽

0개의 댓글