Notice
Recent Posts
Recent Comments
Link
«   2024/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
Tags
more
Archives
Today
Total
관리 메뉴

coding etude

200927 [동기 / 비동기 (synchronous / asynchronous)] 본문

Javascript TIL

200927 [동기 / 비동기 (synchronous / asynchronous)]

코코리니 2020. 9. 27. 16:46

동기/ 비동기는 무엇일까?

한국어 사전을 검색해 보았다. 최소 7가지의 동기라는 단어가 나온다....-_-;;;

 

그 중에서 가장 적절한 말은 (동기 : 같을 동/ 기약할 기 [명사 : 같은 시기. 또는 같은 기간])을 의미한다.

 

그럼 synchronous는 무엇일까??

[synchronous : 동시 발생[존재]하는] 이라는 뜻을 가지고 있다.

 

이 말인 즉, 실행 했을 때 그 결과값이 동시에 발생해야(존재해야) 한다는 말이다.

 

예를들어 커피숍에 들어가서 주문을 하려고 줄을 섰는데.. 첫번째 사람이 커피를 주문하고, 결재를 하고, 커피를 만들고, 커피를 받으면 다음 사람이 주문을 할 수 있는 것이 동기 인것이다.

'커피를 주문 했으니 주문한 커피를 반환해야 한다' // 주문과 받는것이 동시에 이루어 지고 존재한다.

그럼 이런 비정상적인 상황에서 첫번째 사람이 커피를 주문해서 기다리는 것을 Blocking 라고 한다. 

 

이건 또 무슨말인가 하니... 내가 주문하는 것을 앞사람이 막고 있는것이다.. -_-;; (농구나 배구 마냥...)

정리해 보면 동기적인 움직임에서는 항상 blocking가 발생한다는 것이다.

 

그럼 비동기는 무엇일까? 동기와는 반대의 개념이라는 것이 느껴지는가??

바로 주문은 주문대로 반환은 반환대로 이루어 지는것이다.

 

하지만 현실에서 주문한 메뉴에 따라서 만드는 시간이 다르기 때문에 내가 먼저 두유딸기프라프치노를 주문했어도 나 다음 사람이 아.아를 주문했다면... 나보다 뒷사람이 먼저 받는 상황을 많이 봐왔을 것이다.

 

이처럼 프로그램도 순서를 정해 주지 않으면 완성되는 수서대로 값을 반환하게 된다.

현실에서는 어렵지만 컴퓨터의 세계에서는 이 반환 순서를 정해줄수 있다.

let toOrder = function(str){
	setTimeout(function(){
    	console.log(str)
    },
    Math.floor(Math.random() * 100) + 1
    )
}

/* arrow fn을 이용할 수 있다.
let toOrder = (str) => {
	setTimeout( () =>{
    	console.log(str)
    },
    Math.floor(Math.random()*100)+1
    )
}
*/

let printAll = () => {
	toOrder('A')
    toOrder('B')
    toOrder('C')
}

printAll() // 함수 실행

위의 예시에 A, B, C 의 값을 주어서 실행한다면 Math.random에 의해서 반환되는 값은 항상 변할 것이다.

하지만 callback 함수를 사용하여 다음 실행 될 값을 준다면 순서를 정할 수 있다.

 

let toOrder = (str, callback) => {
	setTimeout(() => {
    	console.log(str)
        callback()
    },
    Math.floor(Math.random() * 100) + 1
    )
}

let printAll = () => {
	toOrder("A", () => {
		toOrder("B", () => {
        	toOrder("C", () => {}
        }
     } 
 }    

위의 방법처럼 인자에 함수를 주어 연속적으로 실행 되게 만들어 주면 A, B, C 가 각각 다르게 종료되더라도 지정한 순서대로 반환이 된다.

하지만 값이 많을때는 callback 지옥에 빠질 수 있다.

그래서 나온것이 Promise 이다.

 

Promise란 무엇일까?? (developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise)

[프로미스가 생성될 때 꼭 알 수 있지는 않은 값을 위한 대리자로, 비동기 연산이 종료된 이후의 결과값이나 실패 이유를 처리하기 위한 처리기를 연결할 수 있도록 합니다. 프로미스를 사용하면 비동기 메서드에서 마치 동기 메서드처럼 값을 반환할 수 있습니다. 다만 최종 결과를 반환하지는 않고, 대신 프로미스를 반환해서 미래의 어떤 시점에 결과를 제공합니다.]

MDN에서는 다음과 같이 설명하고 있다. 

아직 알수는 없지만 연산이 종료되면 그값을 알려줄께!! 라는 보증수표같은 녀석인 것이다.(그래서 약속??)

@ promise constructor : 아직 값이 정해지지 않은 함수를 묶을 때 사용 함.

// ex) Promise((resolve, reject) => {}) => resolve, reject 함수를 가지고 있다.

 

Promise 에는 3가지 종류가 있는데 

1. pending : 이행되지 않은 초기 상태 이거나 대기 상태

2. fulfilled : 연산이 성공적으로 완료됨.

3. rejected : 연산이 실패함.

 

여기서 pending 된 연산을 .then() 메서드로 연결해서 사용 할 수 있다. .then을 계속 연결해서 리턴값을 다음 then에 전달 하기 때문에 chaining method 라고도 한다. .then의 결과값은 Promise 를 반환하기 때문에 비동기적 연산이 이루어 지는 것이다. 

 

여기서 궁금증!! 그럼 .then() 이라는 녀석은 어떤 녀석일까??(developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise/then)

.then()의 결과값은 Promise를 리턴하고 매개변수 resolve/ reject 를 받는다고 되어있다.

매개변수 중 하나 이상을 생략했거나 함수가 아닌 값을 전달한 경우then은 핸들러가 없는 것이 되지만 오류를 발생하지는 않습니다. then 바로 이전의 Promise가 then에 핸들러가 없는 상태로 완료(이행이나 거부)했을 경우, 추가 핸들러가 없는 Promise가 생성되며, 원래 Promise의 마지막 상태를 그대로 물려받습니다.

 : 요약(매개변수가 꼭 resolve/reject 가 아니더라도 이전의 Promise의 마지막 상태를 물려받는다.)

이 말인 즉, 이전 Promise의 마지막 값을(return값)을 그대로 물려받아서 실행하고 조건에 따라 또 다른 return값을 반환한다니.. 정말 멋진 녀석이 아닐 수가 없다...

Promise / then / catch의 진행

 그래서 위의 예제를 promise로 바꿔보면 

let toOrder = (str) => {
  return new Promise((resolve, reject) =>{
	setTimeout(() => {
    	console.log(str)
        resolve()
    },
    Math.floor(Math.random() * 100) + 1
    )
  }
}

let printAll = () => {
  toOrder("A") 
  .then(() => {
  	return toOrder("B")
  })
    .then(() => {
      return toOrder("C")
  })
}

printAll() // 함수 실행

.then을 이용하여 A가 끝나면 then을 실행해줘 의 의미로 연속해서 순차적인 비동기적 실행이 가능한 것이다.

여기서 return의 값이 있다면 그 값은 다음 then 의 매개변수가 되지만 굳이 매견변수를 넣지 않으면 단순 연속해서 실행하는 결과를 주기 때문에 then을 잘 활용하면 굉장히 편리한 연산이 가능할 것이다.

 

위의 예시도 역시 then 지옥에 빠져들게 되는 경우가 오게 된다. (예시는 구글링면 바로 나오기 때문에 따로 예시를 쓰지 않아요~)

 

이런 작업들을 조금더 간소하게 하기 위해 Promise method 가 존재한다.

 

.all(iterable) 

.resolve(value)

.reject(reason)

.any(iterable)

.race(iterable)

.allSettled(iterable)

 

각각의 사용법은 한번씩 테스트 해보고 익혀 두자.

 

최근 ES8에서 새로나오 async / await 를 사용하면 한결 더 편리한 연산이 가능해 진다.

 

promise를 반환하는 함수를 사용하는 방법은 동일하지만 함수를 실행할때 앞에 꼭 async 를 적어주고, 비동기적 실행 시 await를 사용하여 함수를 실행해야 한다. 

// 함수 선언

function a(){
	return new Promise((resolve, reject) => {
    	setTimeout(() => {resolve('1. go to shcool')}, 100)
    })
}
function b(){
	return new Promise((resolve, reject) => {
    	setTimeout(() => {resolve('2. sit and study')}, 2000)
    })
}
function c(){
	return new Promise((resolve, reject) => {
    	setTimeout(() => {resolve('3. eat lunch')}, 1000)
    })
}
function d(){
	return new Promise((resolve, reject) => {
    	setTimeout(() => {resolve('4. go to home')}, 500)
    })
}

// 함수 실행
const result = async () => {
	const one = await a();
    const tow = await b();
    const three = await c();
    const fore = await d();
}
result();

// 실행 결과
1. go to shcool
2. sit and study
3. eat lunch
4. go to home

위의 예제 처럼 사용이 가능 하다. 

또한, await 함수 뒤에 .then 을 사용하여 값의 가공도 가능하다.

 

이처럼 비동기적 진행은 다양한 방법을 가지고 있지만 모두 다룰수 있어야 한다. 꼭 숙지하고 다시 한번 공부해보자.,

'Javascript TIL' 카테고리의 다른 글

201006 [Server / node.js]  (0) 2020.10.06
201006 [Client / Server]  (0) 2020.10.06
200927 [parse / parsing / JSON / json()]  (0) 2020.09.27
200910 [Linked List]  (0) 2020.09.10
200909 [OOP : Object-Oriented Programming]  (0) 2020.09.09