[Async, 비동기와 동기] Promise에서 Await까지

calm·2018년 10월 25일
19
post-thumbnail

비동기/동기에 대한 정의와 콜백함수,콜백지옥을 거쳐
Promise가 도입된 이유 그리고 간략히 Async Await까지 순서대로 정리하려고 합니다.
코드 보다는 개론적인 의미에 치중해 작성된 글입니다.
Promise 를 공부하다 어떤 개념으로 어떻게 여기까지 오게 됐을까 궁금해 이 글을 작성하게 됐습니다.

동기(지금) VS 비동기(나중)

동기와 비동기의 구분은 요청받고 응답받는 시간대의 차이라고 생각합니다
요청하고-응답받는 시간을 하나의 박스(box)라로 정의한다면,
동기는 박스 안에서 움직이고, 비동기는 박스를 벗어나 작동되는 원리 라고 생각합니다.

  • 동기 : 요청과 응답이 같은 시간대 “안에” 고정되어 있어, 요청에 대해 응답이 완료되기까지 프로그램이 정지합니다. 응답을 받고나서야 비로소 다시 진행되는 특성을 가집니다.

  • 비동기 : 요청-응답 간 결합이 자유로워 프로그램이 응답 받기 위해 대기하지 않고 쿨하게?! 자기 갈길?! 가는 특성입니다. 언젠간 응답을 받을테고 다음 로직을 수행 합니다.

동기(synchronous)

요청을 하는 시기와 응답을 받는 시기가 일치한다는 것입니다.
간단히 말해 요청을 하면 (바로) 응답을 받는다는 의미입니다.

하지만 응답을 바로 받을 수 있을까요? 그럴 수도 있고 그렇지 않을 수도 있겠죠
왜냐하면 요청을 받는 곳이 처리속도가 어떠냐는 아무도 모르기 때문입니다. 이런 이유로 프로그램은 응답까지 대기시간을 필요로 합니다.
어플리케이션이 잠시 멈춘다는 의미입니다.예를 들면 클릭한 버튼이 응답을 받기까지 작동이 안됩니다.버튼을 클릭 했는데,어떤 이유에서인지 응답(결과)이 없이 화면이 정지된 그런 상황입니다.

비동기(asynchronous)

요청 한 내용을 언젠간 응답해 줄 것이라는 약속을 의미합니다.

요청과 응답이 다른 시간대 존재하기 때문에, 요청내용에 대해 지금 바로 혹은 당장 응답받지 않아도 됩니다.(바로 응답이 와도 됩니다)
요청과 응답이 다른 시간대 존재하기 때문에, 요청내용에 대해 지금 바로 혹은 당장 응답받지 않아도 됩니다.(바로 응답이 와도 됩니다)

콜백함수("call" + "back")

"콜백함수는 자바스크립트의 비동기성을 표현하고 관리하는 가장 일반적인 기법이자 가장 기본적인 비동기 패턴이다(You don't know Js)"

그럼 콜백함수란 무엇일까?
"요청 처리가 완료되어 (다시) 사용하세요 !" 라는 신호라고 생각합니다.
즉, 콜백함수에서 콜백이란 이름이 별로 있는 것이 아니라, 함수(function)가 있는데, 사용되는 목적/용도가 "call + back" 이라는 것입니다
(아직도 그 뜻을 정확히는 모르지만 대충은 이런 느낌이지 않을까 생각한다는 의미입니다.)

즉. 콜백함수가 실행됐다는 것으로 요청한 작업이 끝났음을 알리고, 작업의 결과물을 콜백함수를 통해 사용가능하게 됩니다.

사용 된 예로, 클릭 이벤트가 발생할 때 출력되는 콜백 함수를 본적이 있을 것입니다.

콜백헬(hell), 피라미드 무덤

콜백함수가 늘어나면 늘어날 수록 코드의 깊이가 늘어나 더이상 헤어날 수 없다는 유머 입니다.
코드 관점에서 콜백함수는 중첩으로 들여쓰기(nesting)가 반복되 가독성이 떨어지게 됩니다.이런 중첩된 모습이 꼭 피라미드 같다고 해서 피라미드 무덤 이라고 합니다.
무덤은 빠지면 헤어나올 수 없는 곳이죠?

Promise 도입목적

콜백헬, 피라미드 무덤 처럼 콜백함수로 꼬여버린 함수에서
우리를 구원할 새로운 개념이 도입됐습니다.
그것은 Promise 입니다.

Promise가 도입 된 것이 비단 그런 이유뿐일까요,

  • 첫째. 비동기 처리는함수에서 처리된 결과값을 반환할 경우, (비동기)함수에서 찾을 수 밖에 없어 코드가 복잡할 경우 어려움이 있습니다. Promise는 구조가 간단해 반환값을 찾아 사용하기 쉽습니다.

  • 둘째. 비동기 처리를 위한 콜백패턴이 처리순서를 보장하지 않습니다.

  • 셋째. 에러처리에 대한 한계가 있습니다.
    에러는 호출자 방향으로 전파되는데 만약 호출자가 사라진다면 어떨까요?
    다시 말해 비동기처리 함수는 콜백함수를 호출하고 그것이 완료되기 전에 바로 호출스택을 빠져나갑니다. (콜백)함수를 호출한 호출자가 사라지는 겁니다.
    만약 비동기처리 함수에서 에러가 발생할 경우. catch 구문에서 에러케치가 어려워 프로세스가 종료 될 수도 있습니다.

Promise는

promise로 구현된 비동기 처리 함수는
콜백을 예측 가능한 패턴으로 사용하도록 도와주며,
콜백함수 안에서 생성된 프로미스 객체를 활용해 콜백함수가 성공,실패,오류 각각의 경우에 따라 후속 처리를 할 수 있습니다.
순차적이지 않는 비동기함수의 실행순서를 제어할 수 있게 도와줍니다.
콜백패턴에 비해 코드 가독성이 좋고 반환된 결과물을 사용하기 편합니다.

Promise 생김새

[프로미스는 구조]
크게 선언부와 동작부로 구성되는데,
선언부는 프로미스 객체를 만드는 곳이고 동작부는 선언된 것을 호출하는 역할입니다.

프로미스를 만드는 방법은 다음과 같습니다.
구현하려는 비동기 함수안에 Promise 객체를 만드는(new) 로직을 넣습니다.
프로미스 생성자 함수에 비동기 처리를 담당할 함수를 인자로 넣고,(=new Promise 생성자 함수 안에 비동기 처리함수를 인자로 넣고) 다시 그 처리 함수는 resolve와 reject 라는 인자를 전달 받습니다.
이 생성자 함수를 new를 통해 인스턴스화 된 객체가
바로 프로미스 입니다.

비동기 처리함수가 어떤 결과값을 갖는냐에 따라,

  • 생성된 프로미스 객체는 아래와 같은 3가지 상태값을 갖습니다.
  • pending(비동기 처리 로직이 아직 완료되지 않는 상태)
    new Promise로 Promise가 생성된 직후부터 resolve나 reject가 호출되기 전까지의 순간을 pending 이라고 합니다.

  • fullfilled(처리가 완료되어 프로미스가 결과값을 반환한 상태)
    만약 비동기 처리함수 값이 성공이라면 resolve 메소드가 호출되고,resolve 메소드의 인자로 설정한, 비동기 함수의 결과값이 전달된다. 이 결과값은 then을 통해 후속 처리된다.

  • Rejected(처리가 실패하거나 오류가 발생한 상태)

[성공했을 경우]
비동기 처리함수가 성공이라면 ->resolve 메소드 실행 -> 이때 resolve 메소드 인자에 이미 설정한 처리함수의 결과값이 (resolve 메소드를 통해) 이동 -> then메서드를 통해 성공의 후속처리 실행

Promise 사용과 동작순서

[resolve()/reject()메서드에 인자가 없을 경우]

코드는 블로그 "자바스크립트 비동기 프로그래밍 promise, async, await" 내용을 사용했습니다.

Promise 처리순서
(위 링크 내용을 순서별로 정리했습니다.)
(실행되는 순서 이외의 내용은 블러(blur)처리 했습니다)

[1] create()함수를 호출하면, function create(){...} 부분은 생성이되고 실행하지 않습니다,아래 create()가 실행됩니다.
create()함수에 인자값을 넣어서 호출할 수 있습니다. 그럼 이 값을 받기 위해서는 Promise 선언부 함수가 값을 받을 매개변수가 있어야겠죠?

[2] create()가 호출되면서 내부에 선언되었던 코드가 실행됩니다. new Promise()의 인스턴스가 리턴되며 콜백함수로 선언해 놓은 function create(){...}이 실행됩니다.
resolve()는 선언되었지만 성공조건이 충족되기까지 실행되지 않았고 "conseol.log("step1")만 실행됩니다.

[3] return을 통해 생성된 인스턴스를 반환합니다. resolve()는 나중에 호출할 수 있는 환경이 되면 실행됩니다. function create(){...}가 끝나면 console.log('stetp2')가 실행된다.
아직 resoleve를 호출 될 상황은 아닙니다.
console.log("step2")가 출력되고 then 내부에 작성된 function()이 실행됩니다. then()을 실행하지 않고 바로 다음 코드를 실행합니다.

[4] create()의 모든 함수가 끝나고 resolve()함수가 호출됩니다. 성공인지 실패인지에 따라 출력되는 then 메서드가 다릅니다.

[resolve()/reject()메서드에 인자가 있을 경우]

Promise로 구현한 비동기 처리함수도 결과물을 반환할 수 있다.
이것을 resolve()/reject()에 인자로 값을 넣어 반환할 수 있다.
인자로 넘어간 값은 then메서드에 인자로 들어간 function(){..}에 들어가 후속처리 할 수 있습니다.

Promise 마무리

Promise로 구현한 비동기 함수가 {..}안의 로직을 마친 후,
그 결과가 성공일 경우 resolve()메서드를, 실패일 경우 reject()메서드를 호출합니다. 만약 함수의 처리결과를 이용해 후속 처리하고 싶다면, resolve()/reject()메서드의 인자로 넣어 then()으로 보내면 됩니다.
resolve()는 함수를 종료하는 역할도 합니다.
Promise를 이용한 다른 API가 있는데 그것은 여기에서 다루지 않습니다.

Async Await

Promise가 기존 콜백지옥에서 코드를 조금은 동기적으로 개선했 지만 코드의 실행순서나 복잡함에 있어서는 손볼 곳이 있었습니다.
그래서 이를 간편하게 만드는 "Async Await"가 도입됐습니다.

사용법이 직관적이고 간편해졌고, 특히 await 라는 키워드가 생겨 실행을 지연하는 기능도 추가됐습니다. 지연기능이 어떤 면에서 장점이고 어떻게 사용하는지 공부해보고 정리해야겠습니다.

다음글은 "Async Await" 에 대해서 다뤄보도록 하겠습니다.

부족한 글이지만 끝까지 읽어주셔 감사합니다.

[참고 링크]
이미지 : https://www.wsj.com/articles/SB10001424052970204770404577082933921432686

블로그 내용:
You don't know JS
비동기/동기: http://nsinc.tistory.com/108

콜백이란/콜백함수 : https://joshua1988.github.io/web-development/javascript/javascript-asynchronous-operation/

프로미스: https://medium.com/@shlee1353/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%B9%84%EB%8F%99%EA%B8%B0-async-await-promise-ae659eb1cb7e
https://poiemaweb.com/es6-promise
https://programmingsummaries.tistory.com/325

profile
공부한 내용을 기록합니다

6개의 댓글

comment-user-thumbnail
2018년 11월 21일

제가 초보라서 읽어도 모르겠네요 ㅠㅠ
정말 이해 하고싶은뎅~ 아흑~

1개의 답글
comment-user-thumbnail
2019년 1월 9일

좋은 글 써주셔서 감사합니다:)

Promise에서 에러 처리를 할 때 .then에서 일어난 에러를 캐치하기 위해서 말씀하신 방법보다는 아래처럼 .catch로 핸들링하는 방식이 좀 더 선호되는걸로 알고있습니다.

create().then(function (result) {
//...
}).catch(function (err) {
console.log(err);
});

제가 알고있는게 맞을까요?

1개의 답글