DEVLOG

동기방식 vs 비동기방식, 콜백함수와 Promise 까지 한번에 훑어보기! 본문

frontend/javascript

동기방식 vs 비동기방식, 콜백함수와 Promise 까지 한번에 훑어보기!

meroriiDev 2021. 4. 18. 21:14
728x90
반응형

데이터 처리 모델의 방식 :: 동기방식 vs 비동기방식

 

동기방식

순차적으로 동작하는 방식

요청을 보낸 후 해당 응답을 받아야 다음 동작을 실행하며 이 동작이 끝날때까지 다음 동작은 대기상태이다.

 

위 그럼 a처럼 카페에서 줄을 서서 커피를 받는 방식으로 비유하는데,

한 동작이 끝날때까지 기다리기 때문에 동작이 느리다는 느낌을 받을 수 있다.

이것은 실제 CPU가 느려지는 것은 아니지만 시스템 전체적인 효율이 저하된다고 볼 수 있다.

 

설계가 간단하고 직관적이라는 장점을 가지지만, 결과를 볼 때까지 아무것도 못하고 대기해야 한다는 단점이 있다!

 

function func1(){ 
  console.log("1번입니다"); 
  func2(); 
} 
function func2(){ 
  console.log("2번입니다"); 
  func3(); 
} 
function func3(){ 
	console.log("3번입니다"); 
} 

func1(); 
//1번입니다 
//2번입니다 
//3번입니다

 

비동기방식

순차적으로 진행하지 않는 방식

요청을 보내고 응답에 관계없이 바로 다음 동작을 실행한다.

 

동기보다 복잡하지만 결과가 주어지는데 시간이 걸리더라도 그 시간 동안 다른 작업을 할 수 있으므로 자원을 효율적으로 사용할 수 있는 장점이 있다.

why need?

클라이언트에서 서버로 데이터를 요청 했을 때, 서버가 그 요청에 대한 응답을 언제 줄지도 모르는데 데이터가 다 받아질때까지 앱이 대기상태로 머물러있을 수 없기 때문에 비동기방식이 필요하다.

 

* 자바스크립트에서 비동기방식이 가능한 이유

자바스크립트는 흔히 알고있듯 싱글스레드로 프로그램이 동작한다.

**싱글스레드**
한 번에 한가지 일만 처리가 가능한 단일 스레드

그런데 동시의 여러 작업이 동작되는 비동기방식은 멀티태스킹 작업일 수 밖에 없는데 어떻게 자바스크립트에서 비동기방식이 가능한걸까?

 

자바스크립트는 웹 브라우저나 Node.js의 자바스크립트 엔진에서 실행이 된다.

이 엔진에는 자바스크립트를 돌리는 하나의 스레드가 존재한다.

또한 이 엔진 뿐만 아니라 자바스크립트 엔진은 Web API를 두었고, 비동기식 처리 모델인 Web API라는 것이 함께 동작하면서 여기에서 setTimeout이나 Ajax등 기다리는 시간이 필요한 일들을 처리한다.

이 Web API들이 자바스크립트 엔진 스레드와는 따로 비동기 처리를 따로 돌면서 콜백함수를 가지고 이벤트 루프에 들어가 처리되는대로 콜백함수를 다시 자바스크립트 엔진으로 돌려보내준다.

example

setTimeout, ajax ...

 

setTimeout

function func1(){ 
  console.log("1번입니다"); 
  func2(); 
} 
function func2(){ 
  setTimeout(
    console.log("2번입니다");
    , 3000
  ); 
  func3(); 
} 
function func3(){ 
	console.log("3번입니다"); 
} 

func1(); 
//1번입니다 
//3번입니다 
//2번입니다

ajax

function getData() { 
  var tableData; 
  $.get('url', function (response) { 
  	tableData = response; 
  }) // $.get()로 데이터를 요청하고 받아올 때까지 기다리지 않고 return 해버림 
  return tableData; 
} 
console.log(tableData) // 따라서 undefined

이때, 비동기방식의 문제점을 확인할 수 있다.

 

비동기방식의 문제점

바로 데이터통신이 되기도 전에 값을 return해버리게 되거나 이 값을 이용하는 어떠한 동작이 동시에 이루어질 경우 undefined값을 사용할 수 밖에 없다.

 

How can I do?

콜백함수를 이용하자!

콜백함수

콜백함수란?

  1. 다른 함수의 인자로서 이용되는 함수
  2. 어떤 이벤트에 의해 호출되는 함수

callback은 쉽게 말하자면 어떤 일을 다른 객체에게 시키고, 그 일이 끝나는 것은 기다리지 않고 끝나고 부를 때까지 다른 일을 하는 것을 말한다.

function plus(x, y, callback) { 
  sum = x + y; 
  callback(sum) 
} 
function print(result) { 
	console.log(result); 
} 
plus( 1, 2, print);

동작순서

  1. plus함수가 실행된다.
  2. plus함수의 매개변수인 1과 2의 연산값이 sum으로 들어간다.
  3. 매개변수인 callback에 들어간 콜백함수인 print가 callback에 들어간다.
  4. print함수가 실행된다.
  5. print함수의 인자로 사용된 sum이 console.log에 들어감
  6. 콘솔에 3이 나옴.
function increase(number, callback){ 
  setTimeout(()=>{ 
    const result=number+10; 
    if(callback){ 
    	callback(result); 
    } 
  },1000) 
} 
increase(0, result=>{ 
	console.log(result); 
});

 

콜백함수 중첩

1초 뒤 result에 10을 더해서 반환하는 함수를 예로 들어볼때 1초에 걸쳐서 10, 20, 30, 40 과 같은 형태로 여러번 반복을 하고 싶을때 콜백함수를 중첩하여 다음과 같이 구현할 수 있다.

function increase(number,callback){
	setTimeout(()=>{
		constresult=number+10;
		if(callback){
			callback(result);
		}
	},1000);
}
console.log('작업시작');

increase(0,result=>{
	console.log(result);
	increase(result, result=>{
		console.log(result);
		increase(result,result=>{
			console.log(result);
			increase(result,result=>{
				console.log(result);
				console.log('작업완료');
			});
		});
	});
});

네! 이런 코드를 콜백지옥이라고 합니다!

 

콜백지옥

콜백, 콜백, 콜백의 반복으로 depth가 깊어지는 코드를 콜백지옥이라고 부른다

이러한 코드는 가독성을 매우 떨어뜨리므로 지양해야한다.

// 콜백지옥, 가독성이 떨어짐
$.get('url', function (response) {
 parseValue(response, fuction(id) {
  auth(id, function (result) {
   display(result, function (text) {
    console.log(text)
   })
  })
 })
})

 

Promise

콜백지옥 같은 코드를 해결하는 방안으로 ES6에 도입된 기능이다 (IE안녕..)

promise 객체를 사용하여 비동기 작업이 완료된 후(성공 혹은 실패) 결과값을 받을 수 있어 이후 처리를 쉽게 컨트롤할 수 있다.

Promise는 함수를 인자로 받으며 인자로 들어온 함수는 다시 resolve(비동기 처리 성공)와 reject(비동기 처리 실패) 2개의 함수를 인자로 받게 된다.

resolve 시 then 메소드, reject 시 catch 메소드의 인자로 넘어간다.

function increase(number){
const promise=newPromise((resolve,reject)=>{
		// resolve는성공, reject는실패
		setTimeout(()=>{
				const result=number+10;
				if(result>50){
				// 50보다높으면에러발생시키기
				const e=newError('NumberTooBig');
				return reject(e);
			}
			resolve(result);// number값에 +10후성공처리
		},1000);
	});
	return promise;
}

increase(0).then(number=>{
	// Promise에서 resolve된값은 .then을통해받아올수있음
	console.log(number);
	return increase(number);
	// Promise를리턴하면
})
.then(number=>{
	//또 .then으로처리가능
	console.log(number);
	return increase(number);
})
.then(number=>{
	console.log(number);
	return increase(number);
})
.then(number=>{
	console.log(number);
	return increase(number);
})
.then(number=>{
	console.log(number);
	return increase(number);
})
.catch(e=>{//도중에에러가발생한다면 .catch를통해알수있음
	console.log(e);
});
728x90
반응형
Comments