콜백함수는 다른 코드의 인자로 넘겨주는 함수이다.
js에서는 나중에 실행하는 함수이기에 콜백함수라고 불린다.
다른 함수의 인자로 넘길 수 있고
리턴 값으로 함수를 쓸 수 있고
변수에 함수를 넣을 수도 있다.
그래서 js에서는 함수를 일급객체라고 한다.
콜백을 받는 함수가 어떻게 동작하느냐에 따라서 동기적, 비동기적일 수 도 있다.
콜백은 나중에 실행하라고 인자를 다른 함수에게 넘겨주고 제어권도 함께 위임한다.
그래서 콜백을 받은 함수는 역할에 따라 받은 콜백을 실행한다.
콜백을 큐에 넣는지 바로 콜 스택에서 실행하는 역할인지에 따라 동기인지 비동기인지 구별이 된다.
[콜백은 '함수'이다.]
콜백함수는 함수이기 때문에 콜백함수로 어떤 객체의 메서드를 전달하더라도 그 메서드는 메서드가 아닌 함수로서 호출된다.
[콜백함수의 특징]
다른함수(A)의 인자로 콜백함수(B)를 전달하면 A가 B의 제어권을 갖게된다.
미리 정해놓은 방식?
1) 어떤 시점에 콜백을 호출할지
2) 인자에는 어떤 값들을 지정할 지
3) this에는 무엇을 바인딩할지 등이다.
규칙에 따라 정확히 호출하지 않으면 원하는 결과를 얻을 수 없게 된다.
var arr = [1, 2, 3, 4, 5]
var obj = {
vals: [1, 2, 3],
logvalues: function (v, i) {
if (this.vals) {
console.log(this.vals, v, i)
} else {
console.log(this, v, i)
}
}
}
obj.logvalues(1, 2) //객체 메소드로 넘겨짐
console.log(arr.forEach(obj.logvalues)) //콜백함수로 넘겨짐
호출은 forEach가 한다.
obj.logvalues가 가리키고 있는 함수만 떼어서 전달을 한것이다.
그걸 받은 forEach역시 함수로써 호출을 하게 된것.
그렇다면 this는 obj가 아닌 전역객체가 담기게 된다.
//window {...} 1 0
//window {...} 2 1
//window {...} 3 2
//window {...} 4 3
그렇다면 obj를 this로 사용하고 싶으면?
arr.forEach(obj.logvalues.bind(obj)) //bind
arr.forEach(obj.logvalues, obj) //thisArg
비동기 연산을 다루는 promise
=> 콜백지옥을 벗어날 수 있다.
(비동기처리는 '특정 코드의 실행이 완료될 때까지 기다리지 않고 다음 코드를 먼저 수행)
[Producer]
const f1 = () => {
return new Promise((res, rej) => {
setTimeout(() => {
res('1번 주문 완료')
}, 1000);
})
}
promise는 class이기에 new키워드를 이용해서 object를 생성한다.
프라미스의 생성자는 excutor라는 콜백함수를 전달해준다.
이때 콜백함수는 콜백함수reject, resolve를 받는다.
실행이 잘 성공했는지 혹은 실패했는지 그럼 성공(resolve) or 실패(reject)의 결과 값이 무엇인지 위 세가지 내용을 미래(비동기 작업이 종료된 후)에 then과 catch를 통해 반환해주겠다고 약속해주는 객체이다.
resolve와 reject는 자바스크립트가 자체적으로 제공하는 콜백이기 때문에 개발자는 이 콜백 함수들을 신경 쓰지 않고 excutor 안의 코드만 작성하면 된다.
[Promise 상태]
프라미스가 만들어지고 종료 될때까지의 상태를 말한다.
Promise의 비동기 작업이 종료된 후, 비동기 처리가 완료 되지 않았다면 Pending, 완료 되었다면 Fulfilled, 실패하거나 오류가 발생하였다면 Rejected 상태를 갖는다.
[consumer]
producer가 제공하는 정보를 기다렸다가 then, catch, finally를 이용해서 값을 받아온다.
[promise와 콜백 함수 방식 다시 살펴보기]
callback은 콜백은 비동기 로직의 처리 결과를 위해서 callback안에서만 처리를 해야한다. callback 밖에서는 비동기에서 온 값을 알 수가 없다.
callback의 문제점은 함수의 중첩이 많아질 수록 가독성이 나빠진다.
promise는 그 자체로 비동기 처리를 위한 객체이다.
excutor 로직이 실행이 된 후 then과 catch로 값을 받아오는게 잘 정의가 되어있지만, template이 존재하지 않기때문에 코드가 복잡해지고 에러 처리같은 작업들이 어렵다는 단점이 있다.
promise도 콜백헬과 마찬가지로 then()지옥이 있다.
Synchronous(동기) Vs Asynchronous(비동기)
async / await
callback과 promise의 단점을 해소하고자 탄생된 async await
asyn-await은 함수형 컴포넌트에 문법적으로 더 잘맞게 되어있다.
프로미스를 조금 더 간결하고 간편하고 그러고 동기적으로 실행되는 것처럼 보이게 만들어준다.
[어떻게 쓰는건지 이해해보자]
서버와의 통신은 요청과 응답의 순서가 보장되지 않기 때문에 비동기 통신이다.
서버에 요청을하면 순차적으로 처리가 완료됨에 따라 응답이 제공된다.
서버에 요청을 한 후 기다리지 않고 다음 행동을 하게 된다.
ex) 서버에게 db를 가져와 tem_data에 저장을 요청 => 해당 값을 보여달라고 요청
이 경우에 서버는 요청만 하고 클라이언트는 서버에게 해당 값을 요청했지만, 받지 못하고 바로 다음 코드가 실행이 되게 된다.
이럴 때 async를 사용한다.
async 함수는 서버에 요청하는 경우 서버로부터 실행 계획을 Promise를 통해 답을 받는 구조로 진행이 된다.
하지만 Promise를 받아도 다음 코드가 실행이 되게 되는데, 이때 await을 사용해서 promise의 답을 받고 다음실행을 한다.
async함수 => promise반환 => await로 promise를 기다림 => 완료
이처럼 서버 응답을 기다린 후 코드를 순차적으로 진행할 수 있게된다.
[중요 사용 방법]
await 는 async 함수 안에서만 동작한다.
async/await 은 Promise 와는 다르게 에러를 핸들링 할 수 있는 기능이 없다. 따라서 try-catch() 문을 활용하여 에러를 핸들링 하여 주어야 한다.
1) 비동기 작업 앞에 await 키워드를 붙여준다.
그러면 메인작업들은 멈추지 않고 await을 가지고 있는 비동기 작업이 결과를 낼 때까지 기다린다.
await 서버에요청
완료후 실행 할 함수
2) try-catch로 예외를 처리