티스토리 뷰

codestates/section2

Unit3 - [JS/Node] 비동기

나아눙 2023. 1. 18. 00:03

JavaScript의 가장 큰 장점 중 하나인 비동기 흐름

ex ) 강아지 구름이와 호빵이가 있다. 한마리씩 산책을 할수있는데 (blocking)

구름이가 산책을 완료를 하고 호빵이가 산책을 시작하게 되었다.

시작 시점과 완료 시점이 같은 상황을 동기적(synchronous)이다.

 

시작 시점과 완료 시점이 같지 않아도 되는 상황을 비동기적이다.(non-blocking)

 

자바스크립트에서 동기와 비동기

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

비동기:‘특정 코드의 실행이 완료될 때까지 기다리지 않고 다음 코드들을 수행하는 것

 

JavaScript는 싱글 스레드 기반으로 동작하는 언어 -> 동기적으로 작동한다.

런타임 환경에서 비동기 처리를 도와줌

*싱글 스레드 기반? 하나의 스레드(처리 단위)만을 사용하는 것

*런타임 ? 소프트웨어 프로그램이 실제로 실행되는 시점

비동기 자바스크립트

1.동작이 완료되는 순서대로 작동하는 코드

2. 순서를 고려하지 않는 코드

 

*setTimeout 함수? 지정한 시간(밀리초 단위) 후에 함수를 실행

 

타이머 관련 API

setTimeout(callback,millisecond) :일정시간 후에 함수를 실행한다.

millisecond후에 callback함수 실행

retrun값 : 임의의 타이머 ID

setTimeout(function () {
  console.log('2초 후 실행');
}, 2000);

clearTimeout(timerId) : setTimeout 타이머를 종료한다.

return 값 : X

const timer = setTimeout(function () {
  console.log('20초 후 실행');
}, 20000);
clearTimeout(timer); 
// setTimeout이 종료됨.

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

return 값 : 임의의 타이머 ID

millisecond 만큼 시간 간격을 두고 반복적으로 콜백함수를 실행함

setInterval(function () {
  console.log('2초마다 실행');
}, 2000);

clearInterval(timerId)

setinterval 타이머 종료

return 값 : X

 const timer = setInterval(function () {
  console.log('2초마다 실행');
}, 2000);
clearInterval(timer);
// setInterval이 종료됨.

비동기로 작동하는 코드를 제어하는 방법

1.Callback

callback함수 이용->비동기 순서 제어

코드가 길어질 수록 복잡해지고 가독성이 낮아지는 Callback Hell

Math.floor(Math.random() * 100) + 1 : 1부터 100 사이의 난수(random number)를 생성

Math.random()은 0과 1 사이의 난수를 생성하는 함수

100을 곱해 0과 100 사이의 난수를 얻는다.

그결과에 1을 더하면 1과 100사이 난수를 얻는다.

Math.floor() : 주어진 수보다 작거나 같은 가장 큰 정수를 반환

따라서 Math.floor()함수로 인해 0~99사이에 정수가 발생하고 +1로 1~99사이 난수가 발생한다.

const printString = (string, callback) => {
  setTimeout(function () {
    console.log(string);
    callback(); //콜백 함수를 부른다.
  }, Math.floor(Math.random() * 100) + 1);
}; //setTime 함수를 사용하여 인자로 받은 String을 출력하는 익명 함수를 랜덤한 시간 후에 실행
//인자로 받은 callback함수를 실행

const printAll = () => {
  printString('s', () => {
    printString('y', () => {
      printString('n', () => {});
    });
  });
};

Callback Hell?

콜백 함수를 중첩하여 사용할 때 발생하는 코드의 깊이가 깊어지고 읽기 어려운 코드를 만들어내는 현상

 

Callback Hell 방지하기 위해 Promise가 사용

 

2.premise

let promise = new Promise((resolve, reject) => { //new 키워드를 통해 promise 객체 생성되면 콜백함수 자동으로 실행
//콜백함수는 resoleve,reject함수를 인수로 전달
	// 1. 정상적으로 처리되는 경우
	// resolve의 인자에 값을 전달
	resolve(value); 

	// 2. 에러가 발생하는 경우
	// reject의 인자에 에러메세지
	reject(error);
});

new promise는 Promise객체를 반환한다.

promise객체는 state,result 내부 프로퍼티를 갖는다.

.then , .catch , .finally 의 메서드를 사용해서 내부 프로퍼티를 접근 가능

 

state 

기본 상태 : padding(대기)

콜백함수(executor) 성공적으로 작동 -> fulfilled

에러가 발생 -> rejected

 

result

처음 : undefined

콜백함수(executor) 성공적으로 작동 -> resolve(value) 호출됨 -> value로 변경

에러 발생 ->reject(error)가 호출 -> error로 변경

 

.then , .catch , .finally 메서드

.then

콜백함수가 성공적으로 작동 -> resolve(value)호출 -> .then메서드로 접근 가능

.then 안에서 리턴한 값이 promise -> promise의 내부 프로퍼티 result를 다음 .then의 콜백함수의 인자로 받아옴

.then 안에서 리턴한 값이 promise X -> 리턴한 값을 .then의 콜백함수의 인자로 받아옴

let promise = new Promise((resolve, reject) => {// new Promise는 promise객체를 반환한다.
//promuse객체를 생성했으면 callback함수(resolve,reject) 실행
	resolve("success");  //콜백함수 정상적으로 실행-> resolve함수 호출-> result값은 success
});

promise.then(value => {  //콜백함수가 성공적으로 작동 -> then에 접근가능 -
//-> Promise면 result를 .then의 콜백함수 인자로 받아옴
//-> Promise가 아니면 리턴한 값을 .the의 콜백함수 인자로 받아옴
	console.log(value);
	// "success"
})

.catch

에러 발생 ->reject(error)가 호출-> .catch 메서드로 접근 가능

let promise = new Promise(function(resolve, reject) { //new Promise는 promise 객체 반환 , 
//객체 생성하면 콜백함수(resolve, reject) 자동으로 실행 
	reject(new Error("에러")) //콜백함수 에러발생 -> reject함수 호출 -> result값 error
});

promise.catch(error => {
	console.log(error);
	// Error: 에러
})

.finally

 

정상 처리 여부 상관없이 .finally로 접근 가능

let promise = new Promise(function(resolve, reject) {//new Promise는 Promise객체를 반환한다.
//Promise객체를 생성하면 자동 실행
	resolve("success"); //콜백함수가 정상적으로 동작 -> resolve함수 호출 -> result값 suceess
});//하지만 정상 처리 여부 상관없이 .finally메서드로 접근가능하다.

promise
.then(value => {
	console.log(value);
	// "success"
})
.catch(error => {
	console.log(error);
})
.finally(() => {
	console.log("success or fail 작동");
	// "success or fail 작동"
})

Promise chaining

.then , .catch , .finally의 메서드들을 promise로 반환하여 비동기 작업을 순차적으로 진행함

let promise = new Promise(function(resolve, reject) {
	resolve('success');
	...
});

promise
  .then((value) => { 
    console.log(value);
    return 'success'; //각 then을 통해 전달받은 value는 이전 then에서 return한 값
  }) //.then메서드는 새로운 객체반환
  .then((value) => {
    console.log(value);
    return 'success';
  })
  .then((value) => {
    console.log(value);
    return 'success';
  })
  .catch((error) => {//에러가 발생할 경우 처리
    console.log(error);
    return 'fail';
  })
  .finally(() => {
    console.log('success or fail 작동');
 });
 
 //모두 promise 객체를 반환 return값을 받아서 들어감

? 어디로 return값을 받고 들어가는지를 알고싶었다.

.then() 메서드는 기존의 Promise 객체에서 resolve() 메서드로 전달된 값을 처리하는 함수를 전달하면, 새로운 Promise 객체를 반환하여 이어서 작업을 진행하다.

각 then에서 return된 값은 다음 then의 value로 전달

Promise.all()

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

const promiseOne = () => new Promise((resolve, reject) => setTimeout(() => resolve('2초'), 2000));
const promiseTwo = () => new Promise((resolve, reject) => setTimeout(() => resolve('3초'), 3000));
const promiseThree = () => new Promise((resolve, reject) => setTimeout(() => resolve('5초'), 5000));
//2초 걸리는 코드 , 3초걸리는 코드 , 5초걸리는 코드 -> promise.all로 5초가 걸린다.

인자를 배열로 받는다.

정상적으로 처리 -> 결과를 배열로 저장해 새로운 promise 반환

기존 코드 보다 간결 , 코드 중복 되는 현상 X

5초안에 모든 작업 종료

// 기존
const result = [];
promiseTwo()
  .then(value => { //then을 통해 전달받은 vlaue는 2초
    result.push(value);
    return promiseThree();
  })//then메서드 새로운 객체 반환
  .then(value => { //then을 통해 전달받은 vlaue는 3초
    result.push(value);
    return promiseFive();
  })
  .then(value => { //then을 통해 전달받은 vlaue는 5초
    result.push(value);
   console.log(result);  
	 // ['2초', '3초', '5초']
  })
  /*-------------------------------------------------------*/
  // promise.all
Promise.all([promiseTwo(), promiseThree(), promiseFive()]) //배열에 함수를 넣어줌
  .then((value) => console.log(value)) 
  // ['2초', '3초', '5초'] 
  .catch((err) => console.log(err));
  
  /*----------------------------------------------------------*/
  Promise.all([
  new Promise(
    (resolve, reject) => setTimeout(() => reject(new Error('에러1'))),
    2000
  ),
  new Promise(
    (resolve, reject) => setTimeout(() => reject(new Error('에러2'))),
    3000
  ),
  new Promise(
    (resolve, reject) => setTimeout(() => reject(new Error('에러3'))),
    5000
  ),
])
  .then((value) => console.log(value))
  .catch((err) => console.log(err));

 

인자로 받는 배열 안에 있는 Promise 중 하나라도 에러 -> 나머지 Promise의 state 상관없이 즉시 종료

 

Promise Hell 

여러개 Promise와 then()메서드를 중첩으로 사용한다. 

코드가 길어질수록 복잡해지고 가독성이 낮아지는 Promise Hell이 발생

 

Async/Await

복잡한 Promise 코드를 간결하게 작성

// 함수 선언식
async function funcDeclare() { //asyns함수 내에 await 키워드 사용 
	await 작성하고자 하는 코드
	...
}

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

// 화살표 함수
const Arrow = async () => {
	await 작성하고자 하는 코드
	...
}

await 키워드가 작성된 코드가 동작하고 나서 다음 코드 동작 


Node.js

Node.js는 "비동기 이벤트 기반 JavaScript 런타임

 

Node.js 모듈 사용법

Node .js 내장 모듈에는 다양한 모듈이 존재한다.

DNS 모듈 ? 

파일 시스템 모듈 : 파일을 읽거나 저장하는 기능을 구현

readFile 메서드 : 파일 읽기

writeFile 메서드 : 파일 저장

 

Node.js에서 다른 파일 불러오는 require

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

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

underscore ? 서드 파티 모듈 

서드 파티 모듈 ? 기존 기술을 재사용하여 개발 시간을 단축시키거나 특정 기능을 쉽게 구현할 수 있도록 도와

이를 다운받기 위해 npm을 사용한다.

npm install underscore

 

메서드 fs.readFile 은 로컬에 존재하는 파일을 읽어온다.

비동기적으로 파일 내용 전체를 읽습니다.

fs.readFile(path[, options], callback)

파일을 읽기 위한 path를 첫번째 인자로 전달

  • path \<string> | \<Buffer> | \<URL> | \<integer>

파일 이름

 

options는 선택적으로 전달할 수 있으며, 파일 인코딩, 파일 크기 등을 설정할수 있음

  • options \<Object> | \<string>(객체나 문자열)

문자열로 전달 -> 파일 인코딩을 받는다.('utf8')

 

 

callback 함수는 파일 읽기에 대한 처리 ,일을 읽고 난 후에 비동기적으로 실행

  • callback \<Function>
    • err \<Error> | \<AggregateError>
    • data \<string> | \<Buffer>(문자열이나 buffer라는 객체)

에러 발생 X -> null data는 파일의 내용 

 

이렇게 읽은 파일 내용을 출력, 저장, 분석 등의 작업을 진행

 

Q data 에는 문자열이나 Buffer 가 전달됩니다. 어떤 경우에 문자열로 전달되는 것일까요?

s.readFile() 함수는 파일을 읽어들인 후 데이터를 전달할 때, 기본적으로 Buffer 타입으로 전달한다.

하지만, options 인자를 사용하여 인코딩을 설정할 수 있는데, 이때 인코딩을 'utf-8'로 설정하면, 읽은 파일의 내용을 문자열로 전달한다.

 


fetch API : JavaScript에서 웹 서버로부터 데이터를 가져오는 기능을 제공하는 API

비동기 요청 대부분 사례 : 네트워크 요청

특정 URL로부터 정보를 받아오는 역할

 

API fetch를 이용해서 해당 정보를 원격 URL로부터 불러온다.

 


Axis : Node.js를 위한 Promise API를 활용하는 HTTP 비동기 통신 라이브러리

fetch API와 비슷한 역할을 하는 라이브러리인 Axios

 

비교 

Axis FetchAPI
써드파티 라이브러리 설치  별도의 설치 X
JSON데이터 형식으로 자동으로 변환 .json() 메서드 사용

FetchAPI는 빌트인 API(기본적으로 제공되는 인터페이스)

사용법 : npm install axios

 

GET 요청 :정보를 요청하기 위해 사용되는 메서드 

axis(get("url"[,config])

url는 필수

[,config]는 요청시 사용할수 있는 옵션들을 설정

 

ex)Fetch API와 Axios

// Promise ver
fetch('url', { method: 'GET' })
  .then((response) => response.json())
  .then((json) => console.log(json))
  .catch((error) => console.log(error));

// Async / Await ver
// async function request() {
//   const response = await fetch('url', {
//     method: 'GET',
//   });
//   const data = await response.json();
//   console.log(data);
// }

// request();

const appDiv = document.getElementById('app');
appDiv.innerHTML = `
<h1>Fetch API</h1>
`;
/*--------------------------------------------------------------------------------*/
// Promise ver
axios
  .get('https://koreanjson.com/users/1')
  .then((response) => {
    const { data } = response;
    console.log(data);
  })
  .catch((error) => console.log(error));

// Async / Await ver
// async function request() {
//   const response = await axios.get('url');
//   const { data } = response;
//   console.log(data);
// }

// request();

const appDiv = document.getElementById('app');
appDiv.innerHTML = `
<h1>Axios</h1>
`;

 

POST 요청:서버에게 데이터를 내보내기 위해 사용되는 메서드

axios.post("url",[,data[,config]])

url:필수

[,data[,config]] : 요청시 보낼 데이터를 설정

// Promise ver
fetch('url', {
  method: 'POST',
  headers: {
    // JSON의 형식으로 데이터를 보내준다고 서버에게 알려주는 역할입니다.
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ nickName: 'ApeachIcetea', age: 20 }),
})
  .then((response) => response.json())
  .then((json) => console.log(json))
  .catch((error) => console.log(error));

// Async / Await ver
// async function request() {
//   const response = await fetch('url', {
//     method: 'POST',
//     headers: {
//       'Content-Type': 'application/json',
//     },
//     body: JSON.stringify({ nickName: 'ApeachIcetea', age: 20 }),
//   });
//   const data = await response.json();
//   console.log(data);
// }

// request();

const appDiv = document.getElementById('app');
appDiv.innerHTML = `
<h1>Fetch API</h1>
`;
/*---------------------------------------------------------------------------*/
// Promise ver
axios
  .post('url', { nickName: 'so', age: '23' })
  .then((response) => {
    const { data } = response;
    console.log(data);
  })
  .catch((error) => console.log(error));

// Async / Await ver
// async function request() {
//   const response = await axios.post('url', {
//     name: 'ApeachIcetea',
//     age: '20',
//   });
//   const { data } = response;
//   console.log(data);
// }

// request();

const appDiv = document.getElementById('app');
appDiv.innerHTML = `
<h1>Axios</h1>
`;

알게된것

setTimeout 함수는 일정 시간 후에 실행될 함수와 함께 타이머 ID

 

Event Loop: 이벤트 큐에서 이벤트를 가져와 처리하는 과정을 반복하는 루프

 

Callback Queue:이벤트 루프에서 처리해야 할 콜백 함수들을 저장하는 큐(Queue)

 

Callback Queue에는 함수(callback function)가 저장

이벤트 루프는 이벤트 큐에서 처리해야 할 이벤트가 없을 때, Callback Queue를 확인하여 콜백 함수를 실행

이벤트 루프가 처리할 수 없는 비동기 처리를 수행하는데 사용

ex) setTimeout함수를 실행은 특정 함수를 callback queue에 추가하며, 일정 시간이 지나면 이 callback queue에서 해당 함수를 실행한다.

 

 

 

 

 

'codestates > section2' 카테고리의 다른 글

React Twittler State & Props 과제  (0) 2023.01.27
Unit6 - [React] React State & Props  (0) 2023.01.26
Unit5 - [React] React SPA 과제  (0) 2023.01.25
Unit5 - [React] React SPA  (0) 2023.01.24
Unit4 - [React] Intro  (0) 2023.01.20
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함