다른 코드의 인자로 넘겨주는 함수, 인자로 넘겨줌으로써 제어권도 함께 위임했다.
객체의 메소드도 콜백 함수로 전달하면 해당 객체를 this로 바라볼 수 없다.
콜백함수 내부에서 this가 객체를 바라보게 하려면 어떻게 해야될까?
var obj1 = {
name: 'obj1',
func: function () {
var self = this;
return function () {
console.log(self.name);
};
}
};
var callback = obj1.func();
setTimeout(callback, 1000);
var callback2 = obj2.func();
setTimeout(callback2, 1000);
var obj3 = { name: 'obj3' };
var callback3 = obj1.func.call(obj3);
setTimeout(callback3, 1000);
비동기는 동기의 반댓말이다. 동기적인 코드는 현재 실행중인 코드가 완료된 후에야 다음 코드를 실행하는 방식이다.
반대로 비동기 코드는 현재 실행중인 코드의 완료 여부와 무관하게 즉시 다음 코드로 넘어간다.
setTimeout(function (name) {
var coffeeList = name;
console.log(coffeeList);
setTimeout(function (name) {
coffeeList += ", " + name;
console.log(coffeeList);
setTimeout(function (name) {
coffeeList += ", " + name;
console.log(coffeeList);
setTimeout(function (name) {
coffeeList += ", " + name;
console.log(coffeeList);
}, 500, '카페라떼');
}, 500, '카페모카');
}, 500, '아메리카노');
}, 500, '에스프레소'); // 0.5초 간격으로 커피 리스트가 프린트 된다.
위 코드는 전형적인 콜백지옥이다.
개선 시키기 위해 익명 콜백함수에게 모두 이름을 지어주자.
var coffeeList = '';
var addEspresso = function (name) {
coffeeList = name;
console.log(coffeeList);
setTimeout(addAmericano, 500, "아메리카노");
}
var addAmericano = function (name) {
coffeeList += ', ' + name;
console.log(coffeeList);
setTimeout(addMocha, 500, "카페모카");
}
var addMocha = function (name) {
coffeeList += ', ' + name;
console.log(coffeeList);
setTimeout(addLatte, 500, "카페라떼");
}
var addLatte = function (name) {
coffeeList += ', ' + name;
console.log(coffeeList);
}
setTimeout(addEspresso, 500, '에스프레소');
더욱 더 개선시키기 위해 Promise를 사용해보자.
new Promise(function (resolve) {
setTimeout(function () {
var name = "에스프레소";
console.log(name);
resolve(name);
}, 500);
}).then(function (prevName) {
return new Promise(function (resolve) {
setTimeout(function () {
var name = prevName + ', 아메리카노';
console.log(name);
resolve(name);
}, 500)
});
}).then(function (prevName) {
return new Promise(function (resolve) {
setTimeout(function () {
var name = prevName + ', 카페모카';
console.log(name);
resolve(name);
}, 500);
});
}).then(function (prevName) {
return new Promise(function (resolve) {
setTimeout(function () {
var name = prevName + ', 카페라떼';
console.log(name);
resolve(name);
}, 500);
});
});
개선된 Promise 코드
var addCoffee = function (name) {
return function (prevName) {
return new Promise(function (resolve) {
setTimeout(function () {
var newName = prevName ? (prevName + ", " + name) : name;
console.log(newName);
resolve(newName);
}, 500);
});
};
};
addCoffee("에스프레소")()
.then(addCoffee("아메리카노"))
.then(addCoffee("카페모카"))
.then(addCoffee('카페라떼'));
Generator를 사용한 코드
var addCoffee = function (prevName, name) {
setTimeout(function () {
coffeeMaker.next(prevName ? prevName + ', ' + name : name);
}, 500);
};
var coffeeGenerator = function* () {
var espresso = yield addCoffee('', "에스프레소");
console.log(espresso);
var americano = yield addCoffee(espresso, '아메리카노');
console.log(americano);
var mocha = yield addCoffee(americano, '카페모카');
console.log(mocha);
var latte = yield addCoffee(mocha, '카페라떼');
console.log(latte);
};
var coffeeMaker = coffeeGenerator();
coffeeMaker.next();
Promise와 async/await 을 합친 코드
var addCoffee = function (name) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(name);
}, 500);
});
};
var coffeeMaker = async function () {
var coffeeList = '';
var _addCoffee = async function (name) {
coffeeList += (coffeeList ? ',' : '') + await addCoffee(name);
}
}
Refer - Core Javascript