동기/비동기

unow30·2021년 4월 15일
0

computer_science

목록 보기
6/9

동기, 비동기란

  • Synchronous basically means that you can only execute one thing at a time. Asynchronous means that you can execute multiple things at a time and you don't have to finish executing the current thing in order to move on to next one.
  • 동기식이란 기본적으로 한 번에 하나만 실행할 수 있음을 의미합니다. 비동기는 한 번에 여러 작업을 실행할 수 있으며 다음 작업으로 이동하기 위해 현재 작업을 완료 할 필요가 없음을 의미합니다.
  • 유투브 영상이 로딩되는 동안 다른 링크를 클릭할 수 있는 이유는 비동기 요청을 적용했기 때문이다.
  • 웹 내부에서는 아래와 같은 작업이 이루어진다. node eventloof에서 자세히 배운다.
    joshua1988.github.io/web-development/javascript/promise-for-beginners/

callback

// 커피를 만드는 함수. setTimeout 안 console.log()가 출력되며
// 출력 시간은 랜덤하게 실행된다.
let makeCoffie = (coffieOper) =>{
  let ranTime = Math.floor(Math.random() * 100)+1
  //주어진 시간 후에 다음을 실행해라
  setTimeout(() => {
    console.log(coffieOper+" "+ranTime+"ms초");
  }, 
  ranTime
  )
}

//커피 주문 함수, 함수가 실행되면 makeCoffie() 3개가 실행된다.
let coffieOrder = () => {
	makeCoffie("커피콩 그라인딩");
    makeCoffie("스팀추출");
    makeCoffie("커피 완성");
}

//작업은 비동기로 이루어지나 작업 시간이 먼저 끝나는 업무가 먼저 출력되는 문제가 생겼다.
//동기화(setTimeout없이) 실행하면 세 작업은 작성 순서대로 출력되었을 것이다.(그라인딩, 추출, 완성)
coffieOrder()
커피 완성 59ms초
커피콩 그라인딩 73ms초
스팀추출 74ms초

coffieOrder()
커피 완성 8ms초
커피콩 그라인딩 65ms초
스팀추출 62ms초

coffieOrder()
스팀추출 24ms초
커피콩 그라인딩 37ms초
커피 완성 72ms

  • setTimeout이 실행 완료된 순서대로 callback queue에 들어가게 되고 순서대로 출력된다.
  • 비동기로 업무를 실행해도 출력은 순서대로 이루어지도록 callback으로 handle할 수 있다.
  • 업무가 끝나면 나에게 전화(callback)해라, 비동기 끝나면 나에게 일려줘
// 커피를 만드는 함수. setTimeout 안 console.log()가 출력되며
// 출력 시간은 랜덤하게 실행된다.
// callback함수 인자를 추가해서 setTimeout이 완료되면 callback함수가 호출되도록 한다.
let makeCoffie = (coffieOper, callback) =>{
  let ranTime = Math.floor(Math.random() * 100)+1
  //주어진 시간 후에 다음을 실행해라
  setTimeout(() => {
    console.log(coffieOper+" "+ranTime+"ms초");
    //출력 다음에 callback 함수 실행
    callback();
  }, 
  ranTime
  )
}

//커피 주문 함수, 함수가 실행되면 makeCoffie() 3개가 실행된다.
//callback으로 출력 순서를 지정해줄 수 있다.
let coffieOrder = () => {
  makeCoffie("커피콩 그라인딩", () =>{
    makeCoffie("스팀추출", () =>{
      makeCoffie("커피 완성", ()=>{})
    })
  });
}

//출력 순서가 작성 순서대로 진행된다.
coffieOrder()
undefined
커피콩 그라인딩 13ms초
스팀추출 36ms초
커피 완성 92ms초

coffieOrder()
undefined
커피콩 그라인딩 21ms초
스팀추출 42ms초
커피 완성 11ms초

coffieOrder()
undefined
커피콩 그라인딩 26ms초
스팀추출 96ms초
커피 완성 61ms초
  • callback으로 출력 순서를 조절할 수 있으나 업무가 많아진다면 콜백을 사용할 때 코드가 매우 복잡해진다.

promise

  • promise는 일종의 클래스이다. new promise로 인스턴스를 만들 수 있다.
  • promise의 메소드로는 resolve()와 reject()가 있다.
  • callback함수를 받지 않고 new promise를 생성한다.

A Promise is a proxy for a value not necessarily known when the promise is created.
It allows you to associate handlers with an asynchronous action's eventual success value or failure reason.
This lets asynchronous methods return values like synchronous methods.
instead of immediately returning the final value, the asynchronous method returns a promise to supply the value at some point in the future.

Promise는 Promise가 생성 될 때 반드시 알려지지 않은 값에 대한 프록시입니다.
이를 통해 처리기를 비동기 작업의 최종 성공 값 또는 실패 이유와 연결할 수 있습니다.
이를 통해 비동기 메서드는 동기 메서드와 같은 값을 반환 할 수 있습니다.
즉, 최종 값을 즉시 반환하는 대신, 비동기 메서드는 미래의 특정 시점에 값을 제공하겠다는 약속을 반환합니다.

The Promise.resolve() method returns a Promise object that is resolved with a given value.
If the value is a promise, that promise is returned;
if the value is a thenable (i.e. has a "then" method), the returned promise will "follow" that thenable, adopting its eventual state;
otherwise the returned promise will be fulfilled with the value.
This function flattens nested layers of promise-like objects (e.g. a promise that resolves to a promise that resolves to something) into a single layer.

Promise.resolve() 메서드는 지정된 값으로 resolved 해결된 Promise 객체를 반환한다.
value가 promise인 경우 그 promise는 return되고,
value가 실행 가능한 경우(즉, then() 메소드 인 경우), return된 promise는 그 then()의 최종 상태를 채택할 것이다.
그렇지 않으면 return된 promise는 그 값과 함께 fulfilled 될 것이다.
이 함수는 promise와 유사한 객체의 중첩 레이어를 단일 레이어로 병합한다.(e.g. 무언가를 resolve한 promise를 resolve한 promise)

Promise.resolve('Success').then(function(value) {
  console.log(value); // "Success"
}, function(value) {
  // not called
});
===================================================================================
var p = Promise.resolve([1,2,3]);
p.then(function(v) {
  console.log(v[0]); // 1
});
===================================================================================
var original = Promise.resolve(33);
var cast = Promise.resolve(original);
cast.then(function(value) {
  console.log('value: ' + value);// value: 33
});
console.log('original === cast ? ' + (original === cast)); //true

original === cast ? true 이게 먼저 출력된다
value: 33

cast
Promise {<fulfilled>: 33}
original
Promise {<fulfilled>: 33}
===================================================================================

A Promise is in one of these states:
pending: initial state, neither fulfilled nor rejected.
fulfilled: meaning that the operation was completed successfully.
rejected: meaning that the operation failed.

promise의 세 가지 상태
보류: 초기상태, 이행이나 거부가 아닌 상태
이행: 작업이 성공적으로 완료됨
거부: 작업이 실패했음을 의미

// 커피를 만드는 함수. setTimeout 안 console.log()가 출력되며
// 출력 시간은 랜덤하게 실행된다.
// new promise 클래스를 리턴한다.
let makeCoffie = (coffieOper) =>{
  return new Promise((resolve, reject) => {
    let ranTime = Math.floor(Math.random() * 100)+1
    //주어진 시간 후에 다음을 실행해라
    setTimeout(() => {   
      //정상적으로 실행되면 resolve()호출
      resolve(coffieOper+" "+ranTime+"ms초");
    }, 
    ranTime
    )
  })
}

//커피 주문 함수, 함수가 실행되면 makeCoffie() 3개가 실행된다.
//callback으로 출력 순서를 지정해줄 수 있다.
let coffieOrder = () => {
  makeCoffie("커피콩 그라인딩")
    .then((data)=> {
      console.log(data)
      return makeCoffie("스팀추출")
    })
    .then((data) =>{
      console.log(data)
      return makeCoffie("커피 완성")
    })
    .then((data) =>{
      console.log(data)
    })
}
coffieOrder()
undefined
커피콩 그라인딩 95ms초
스팀추출 72ms초
커피 완성 84ms초
coffieOrder()
undefined
커피콩 그라인딩 34ms초
스팀추출 56ms초
커피 완성 7ms초
coffieOrder()
undefined
커피콩 그라인딩 38ms초
스팀추출 26ms초
커피 완성 45ms초
  • return new promise( callback )에서 callback에는 인자로 resolve와 reject만 받는다.
  • 위 코드에서는 reject할 만한 요소가 없어서 (error handling) 관련 코드도 없다.
  • reject할 요소가 있었다면 .then 마지막 부분에 .catch()함수가 들어갔을 것이다.
    .then은 앞에 붙은 함수 실행이 끝나면 실행되는 함수로 내부가 callback 형식으로 되어있다.
  • callback에 들어가는 인자는 .then 앞에서 실행되어 리턴되는 값이다(resolve()에 들어간 값이 then의 인자가 된다).
  • 인자명을 임의로 정하여 then()의 callback안에서 추가작업도 가능하다.
someMethod()
  .then((returnVal) => {
	return returnVal+"추가작업";
  }).then((addedReturnVal) => {
      return addedReturnVal+"또 작업 추가";
    })

Async & await

  • promise function를 await을 사용해서 비동기 함수를 동기적 프로그램처럼 쓸 수 있다.

The await expression causes async function execution to pause until a Promise is settled (that is, fulfilled or rejected), and to resume execution of the async function after fulfillment. When resumed, the value of the await expression is that of the fulfilled Promise.
If the Promise is rejected, the await expression throws the rejected value.

await 표현식은 promise(즉, 이행fulfilled 또는 거부rejected)가 해결될 때까지 비동기 함수 실행을 일시 중지하고 이행 후 비동기 함수의 실행을 재개한다. 다시 시작되면 await 표현식의 value는 이행된 promise value이다.
Promise가 rejected되면 표현식은 rejected value값을 던진다.

// 커피를 만드는 함수. setTimeout 안 console.log()가 출력되며
// 출력 시간은 랜덤하게 실행된다.
// new promise 클래스를 리턴한다.
let makeCoffie = (coffieOper) =>{
  return new Promise((resolve, reject) => {
    let ranTime = Math.floor(Math.random() * 100)+1
    //주어진 시간 후에 다음을 실행해라
    setTimeout(() => {   
      //정상적으로 실행되면 resolve()호출
      resolve(coffieOper+" "+ranTime+"ms초");
    }, 
    ranTime
    )
  })
}

//커피 주문 함수, 함수가 실행되면 makeCoffie() 3개가 실행된다.
//callback으로 출력 순서를 지정해줄 수 있다.
//callback 앞에 async를 붙인 다음 내부에서 함수를 동기화 함수 작성하듯 작성한다.
let coffieOrder = async () => {
  let a = await makeCoffie("커피콩 그라인딩")
  console.log(a)
  let b = await makeCoffie("스팀추출")
  console.log(b)
  let c = await makeCoffie("커피 완성")
  console.log(c)
}

coffieOrder()
Promise {<pending>}
커피콩 그라인딩 70ms초
스팀추출 97ms초
커피 완성 79ms초

coffieOrder()
Promise {<pending>}
커피콩 그라인딩 49ms초
스팀추출 68ms초
커피 완성 86ms초

coffieOrder()
Promise {<pending>}
커피콩 그라인딩 47ms초
스팀추출 20ms초
커피 완성 93ms초

0개의 댓글