내일배움캠프 오늘 학습 내용
- JavaScript 문법 4주차: 콜백 함수와 동기/비동기 처리 Promise, async, await 등 사용 방법
- 4주차 숙제 : Promise .then 으로 적힌 함수로 웹의 정보를 가져오는 프로그램을 async, await를 활용하여 리펙토링을 진행해보았다.
콜백함수
다른 함수의 인자로 넘겨주는 함수. 제어권이 사용자가 아닌 그 함수에게 있기 때문에 호출 시간이나 인자에 대한 제어권을 가지고 해당 함수가 알아서 실행한다. this 또한 제어할 수 있다. 기본적으로는 콜백함수 역시 전역객체를 참조하지만, 제어권을 넘겨받는 해당 함수가 별도로 this를 지정하는 경우 그 함수를 참조하게 된다.
Array.prototype.usermap = function(callback, thisArg) {
//기본 map도 무조건 콜백함수를 받는다. 각 배열의 요소에 대해 주어진 함수를 실행
var mappedArr = [];
for (var i = 0; i < this.length; i++){
//여기서의 this는 호출 주체인 [1,2,3] 을 의미한다. 3번 돈다.
var mappedValue = callback.call(thisArg || global, this[i]);
//새로운 value는 callback 함수를 각각 call해 가져온 값이 된다. call함수의 가장 첫번째 변수는 this
//콜백함수 내에서 this를 명시적으로 사용하기 때문에 이 곳을 명시하게 된다.
mappedArr[i] = mappedValue;
}
return mappedArr;
}
콜백함수에 this를 바인딩 할 때 가장 좋은 방법은 bind를 사용하는 것이다. (저번 강의 참조하기)
메서드 안의 함수를 가져와 콜백함수로 사용하는 것도 역시 함수로서 실행이 되기 때문에 전역변수를 참조하게 되는데, 이때 bind로 실행하게 되면 함수 내의 this는 해당 객체를 참조하게 된다.
var obj1 = {
name: "obj1",
func: function(){
console.log(this.name); //this 유지
},
};
setTimeout(obj1.func.bind(obj1), 1000);
//this는 obj1을 가리키게 된다.
//함수 자체를 bind
var obj2 = {name: "obj2"};
setTimeout(obj1.func.bind(obj2), 1500);
//함수는 obj1에서 가져오지만 bind된 것이 obj2이기 때문에 출력이 obj2가 된다.
콜백함수의 문제점: 콜백함수는 익명함수이기 때문에 콜백함수에서 또 콜백함수를 여러 번 사용하는 경우가 생길 시 들여쓰기가 매우 깊어져 가독성이 떨어지고 유지보수가 어렵게 된다.
동기와 비동기 함수
동기 : 현재 실행코드가 끝나야 넘어간다. 동시적 실행이 불가능하게 된다. 순차적 실행.
비동기 : 여러 가지 내용이 한꺼번에 실행된다. 완료 여부와 무관하게 다음 코드로 넘어간다. ex) setTimeout()
다만 순서가 필요한 동작에서는 비동기식 코딩이 문제가 될 수 있으므로 비동기 함수를 동기적으로 작동하도록 바꿀 수 있어야 한다. -> promise, generator, asyns/await 등을 활용한다.
처리가 성공하거나 실패할 시에 해당 코드로 넘어간다. 넘어가 실행되는 콜백함수엔 해당 resolve에서 넘겨준 인자를 받게 된다.
- 성공 : resolve -> then
- 실패 : reject -> catch
//0.5초마다 커피 이름을 하나씩 더해 출력하는 함수
//함수로 반복되는 부분 만들기
var addCoffee = function(newName){
return function (prevName) { //이 콜백함수의 인자에는 resolve로 넘겨준 인자가 들어간다.
return new Promise(function (resolve) {
setTimeout(function () {
//첫번째와 두번째 작동방식이 다르기 때문에 그것을 나눠준다.
var name = prevName ? `${prevName}, ${newName}` : newName;
//var name = prevName + ", " +newName;
console.log(name);
resolve(name); //resolve가 실행되면서 then으로 name이 넘어가게 된다.
}, 500);
});
}
}
//addCoffee("에스프레소"); ? 이렇게 쓰는 거면 안된다. 처음에는 그 함수의 return이 필요하다.
//그 이유는 Promise부터 시작해야하기 때문이다. then에 들어갈 콜백함수를 기준으로 함수를 만들었기 때문에 resolve로 돌아오는 인자도 없다
//그렇기 위해 두번째 return의 Promise만을 가져오기 위해선 이것을 실행하기 위해선 앞에 함수를 실행해야 한다.
//function(prevName) 부분을 실행해야 값을 얻을 수 있지만 prevName이 없으니 그냥 괄호만 친다.
//addCoffee("에스프레소")(); //그 안의 new promise를 return한 값이 나오게 된다.
//그 뒤로부터는 then의 콜백함수로 실행될 것이고 resolve로 받은 인자가 들어갈 것이기 때문에 설정해주지 않아도 된다.
//실행문
addCoffee("에스프레소")()
.then(addCoffee("아메리카노"))
.then(addCoffee("카페모카"))
.then(addCoffee("카페라떼"));
반복자(iterator)를 생성하여 반복할 수 있다. next라는 메서드를 가지고 있으며 그 때마다 다음으로 나아간다.
yield를 만나면 멈추고 해당 함수가 끝날 때까지 기다리다, next를 만나 다시 나아가는 방식이다.
함수를 선언할 때 앞에 async를 붙여 선언하며 그 함수는 비동기함수이다. 해당 함수 내에서 await를 사용하면 그 메서드가 끝날 때까지 기다려야 한다. 단, 그 메서드는 promise를 반환해야만 한다.
//promise 반환하는 함수
var addCoffee = function(name) {
return new Promise(function (resolve) {
setTimeout(function(){
resolve(name);
}, 500);
});
};
var coffeeMaker = async function () {
var coffeeList = "";
var _addCofffee = async function (name) {
coffeeList += (coffeeList ? ", " : "") + (await addCoffee(name));
};
await _addCofffee("에스프레소"); //해당 출력 다 할 때까지 await로 기다린다.
console.log(coffeeList);
await _addCofffee("아메리카노");
console.log(coffeeList);
await _addCofffee("카페모카");
console.log(coffeeList);
await _addCofffee("카페라떼");
console.log(coffeeList);
};
//함수 실행
coffeeMaker();
'javascript+node.js' 카테고리의 다른 글
| 10/19 Javascript 문법 6, 개인과제 1 (0) | 2023.10.19 |
|---|---|
| 10/18 JavaScript 문법 5 (1) | 2023.10.18 |
| 10/16 JavaScript 문법 3 (0) | 2023.10.16 |
| 10/13 JavaScript 문법 2 (0) | 2023.10.13 |
| 10/12 JavaScript 문법 1 (0) | 2023.10.12 |
댓글