[JavaScript] 콜백함수

고병표·2022년 2월 28일
0

JavaScript

목록 보기
5/9
post-thumbnail

콜백함수(Callback Function)

  • 예제) MDN - Array.prototype.map() 설명 보신 적 있으시죠?
    arr.map(**callback**(currentValue[, index[, array]])[, thisArg])
  • 여러 라이브러리에서 콜백함수인 경우, callback 또는 cb, callbackFn 등등 으로 표기

정의


  • 함수의 매개변수가 함수일 때, 매개변수로 받은 함수를 콜백함수르고 부른다. 끝 -!
  • 고차 함수(Higher Order Function): 매개변수를 함수로 받은 함수. 즉, 외부에서 콜백함수를 전달받은 함수
    • 아래에서 showMessage, Array.map
    • 고차 컴포넌트 Higher Order Component(HOC) 들어보셨나요? 컴포넌트를 매개변수로받아서, 컴포넌트를 반환하는 컴포넌트~~
  • 잠깐 일급함수에 대해 알고 넘어갈게요.

    함수를 다른 변수와 동일하게 다루는 언어는 일급 함수를 가졌다고 표현합니다. 예를 들어, 일급 함수를 가진 언어에서는 함수를 다른 함수에 인수로 제공하거나, 함수가 함수를 반환할 수 있으며, 변수에도 할당할 수 있습니다.

    • 일급함수의 특징
      • 함수를 변수에 할당 가능
      • 함수를 또 다른 함수 인자로 전달 가능
      • 함수의 반환값으로 함수 전달 가능
    • 함수형 프로그래밍 특징 중의 하나가 바로 일급함수 입니다.
      • 자바스크립트 언어 또한 함수형 프로그래밍 기법을 구사할 수 있습니다.

사용


// closeFn가 바로 콜백함수!
// closeFn가 비동기로 쓰인건 아닙니다. (sync callback - 동기 콜백)
function showMessage(msg, closeFn) {
	// 로직로직~~
	
	closeFn(true);
}
// map 함수의 인자인 el => el*2 함수가 콜백함수!
// 얘도 비동기 아닙니다. (sync callback)
[1,2,3].map(el => el*2);
// addEventListener의 두 번째 인자도 콜백함수!
// 얘가 바로~ 비동기로 동작! (async callback)
window.addEventListener('keydown', e => {
	// 로직
});
// setTimeout 함수에 넘긴 익명함수가 콜백함수!
// Hello 또한 3초뒤에 나오죠. 비동기 동작! (async callback)
setTimeout(function(){ 
	alert("Hello"); 
}, 3000);
  • 콜백함수라고 해서 꼭 비동기 동작에 쓰이는 것이 아닙니다.
  • 콜백이 비동기 작업할 때 많이 쓰이다보니, 엮어서 어렵게 느껴지죠.

콜백지옥 (Callback Hell)

현실세계의 코드


  • 요즘은 콜백지옥을 벗어나기 위한 좋은 기법이 많기 때문에, 옛날 옛적 jQuery($) 예제를 가져왔습니다.
$.get('https://api.test.com/proudcts', function(response) {
	var firstProductId = response.products[0].id;

	$.get('https://api.test.com/proudct/comments?id='+firstProductId, function(response) {
		var firstCommentId = response.comments[0].id;
	
		$.get('https://api.test.com/proudct/comment/likes?id='+firstCommentId, function(response) {
			var likes = response.likes;
			var likesCount = likes.length;

			// 첫번째 상품의 -> 첫번째 후기의 좋아요 수 화면에 적용!
		});
	});
});
  • 상품목록을 가져와서 → 그 중에 첫 번째 상품의 댓글을 가져와서 → 그 중 첫번째 코멘트의 좋아요 갯수를 알고 싶을 때!

상황


  • 상품 목록 페이지인데, 목록 정보에 후기 정보도 같이 보이는 경우
    [{
    	"id": 1,
    	"name": "운동화",
    	"price": 30000
    	"comments": [{ 
    		"comment": "강추합니다",
    		"username": "Kim",
    		"likes": [{ 
    			"like": true,
    			"username": "lee"
    		}]
    	}]
    }]
    → 위와 같이 한번만 api를 호출하고, 모든 정보가 왔었으면 좋았을텐데.. → 아래와 같이 상품목록 따로, 후기따로 api가 3개로 나뉘어져 있다.
    [{
    	"id": 1,
    	"name": "운동화",
    	"price": 30000
    }]
    [{
    	"comment": "강추합니다",
    	"username": "Kim"
    }]
    [{
    	"like": true,
    	"username": "lee"
    }]
    • 프론트에서 처리하기 굉장히 비효율적이죠? 일단 기획도 api도 이상한 상황입니다.
    • 어쨋든 기획이 이러면 개발 해야죠.
      • (아니면, 백엔드랑 얘기해서 수정해야 하는데 → 하지만 인생은 원하는대로 흘러가지 않는다.. )
  • 생각해보자
    1. 상품 목록을 가져온다.
    2. 가져온 상품 목록 중에서 첫 상품의 id로 해당 상품의 후기 api를 호출한다.
    3. 가져온 후기 중에서 첫 후기의 id로 좋아요 수를 가져오는 api를 호출한다.

콜백지옥 코드


$.get('https://api.test.com/proudcts', function(response) {
	var firstProductId = response.products[0].id;

	$.get('https://api.test.com/proudct/comments?id='+firstProductId, function(response) {
		var firstCommentId = response.comments[0].id;
	
		$.get('https://api.test.com/proudct/comment/likes?id='+firstCommentId, function(response) {
			var likes = response.likes;
			var likesCount = likes.length;

			// 첫번째 상품의 -> 첫번째 후기의 좋아요 수 화면에 적용!
		});
	});
});
  • 정말 흔하디 흔했던 코드다.

그나마 가독성을 올린 리팩터링된 코드


function fetchCommentLikes(commentId) {
	$.get('https://api.test.com/proudct/comment/likes?id='+commentId, function(response) {
		var likes = response.likes;
		var likesCount = likes.length;

	});
}

function fetchComments(productId) {
	$.get('https://api.test.com/proudct/comments?id='+productId, function(response) {
		var firstCommentId = response.comments[0].id;
	
		fetchCommentLikes(firstCommentId);
	});
}

$.get('https://api.test.com/proudcts', function(response) {
	var firstProductId = response.products[0].id;

	fetchComments(firstProductId);
});
  • 그래도 흐름을 하나하나 따라가야 해서 보기가 어렵습니다.

0개의 댓글