이 글은 PC 버전 TISTORY에 최적화 되어있습니다.
서론
AJAX에 대해서 공부하던 중 StackOverFlow AJAX의 기본을 이해하기 좋은 질문이 있어서 번역합니다.
Q. 비동기식 XMLHttpRequest에서 어떻게 결과를 얻을까요?
다음과 같은 코드가 있습니다. ajax 요청에 대한 결과를 담고 result를 리턴하는데 왜 undefined가 나올까요?function foo() {
var result;
$.ajax({ url: '...',
success: function(response) {
result = response;
// return response; // <- I tried that one as well
}
});
return result;
}
var result = foo(); // It always ends up being `undefined`.
function foo() {
var result;
$.ajax({
url: '...',
success: function(response) {
result = response;
// return response; // <- I tried that one as well
}
});
return result;
}
var result = foo(); // It always ends up being `undefined`.
A. 당신이 직면한 문제
AJAX에서 A는 asynchronous를 의미합니다. 이건 요청을 보낼 때(다르게 표현하면 응답을 받을 때) 평범한 실행 흐름을 따르지 않는다는 거죠. 당신의 예에서 .send는 즉시 return하고 다음 statement인 return result; 로 넘어가고, 그것은 당신이 정의한 success가 실행되기도 전에 실행될 것 입니다. 이건 당신이 반환을 할 때, 당신이 정의한 success란 리스너가 실행되지 않았기 때문에 undefined가 뜨는 것 입니다.여기 간단한 예가 있습니다.function getFive(){
var a;
setTimeout(function(){ a=5; },10);
return a;
}a라는 값은 a=5라는 구문이 실행되기 전에 반환되기 때문에 undefined로 반환되겠죠. AJAX와 바로 이와같이 동작합니다. 서버로부터 원하는 데이터를 받기 전에 값을 반환하고 있는 것입니다.
해결책 있다면 코드를 re-actively하게 짜는 것입니다. 당신의 프로그램이 원하는 계산이 언제 끝났는지 알려주는 것이죠.function onComplete(a){ // 당신의 코드가 완료되면 실행할 함수
alert(a);}
function getFive(whenDone){
var a;
setTimeout(function(){ a=5; whenDone(a); },10);
}이건 CPS로 불립니다. 기본적으로 getFive는 동작이 끝나면 react하게 우리의 코드에 완료를 알려줄 수 있습니다. 마치 우리의 AJAX 호출처럼요.
사용 방법은 다음과 같습니다.getFive(onComplete);
function getFive(){
var a;
setTimeout(function(){
a=5;
},10);
return a;
}
function onComplete(a){ // 당신의 코드가 완료되면 실행할 함수
alert(a);
}
function getFive(whenDone){
var a;
setTimeout(function(){
a=5;
whenDone(a);
},10);
}
가능한 해결책
여기에는 기본적으로 2가지 해결책이 있습니다.
- AJAX를 synchronous하게 호출합니다. (SJAX라고 부릅시다).
- 당신의 코드가 잘 동작하게 적절한 callback을 넣어 다시 짭니다.
1. Synchronous AJAX - 이건 절대 하지맙시다.
MDN에서는 이 같은 방법을 쓰지 말라고 합니다. 요약하자면 이러한 동작은 유저의 브라우저가 서버의 응답을 받을 때까지 멈추게 만들고, 그로인한 안 좋은 사용자 경험을 생성하게 합니다. 원문을 조금만 발췌하자면 다음과 같습니다.
XMLHttpRequest supports both synchronous and asynchronous communications. In general, however, asynchronous requests should be preferred to synchronous requests for performance reasons.In short, synchronous requests block the execution of code... ...this can cause serious issues...
당신이 꼭 해야겠다면 다음과 같이하면 됩니다.
var request = new XMLHttpRequest();
request.open('GET', 'yourURL', false); // false 옵션이 동기식으로 동작시키겠다는 말.
request.send(null);
if (request.status === 200) {// HTTP가 잘 동작되었다는 뜻.
console.log(request.responseText);
}
2. 코드 다시 짜기
당신의 함수가 callback을 받도록 합시다. 아래의 예제 코드에서 foo가 callback을 받게 수정해봅시다. foo의 완료를 어떻게 코드가 알 수 있게하는지 보여드리죠.
전:var result = foo();
// 결과에 따라 달라지는 코드
후:foo(function(result) {
// 결과에 따라 달라지는 코드
});
여기서는 익명함수를 썼지만 아래와 같이 새로 정의해서 넘겨도 좋겠죠.function myHandler(result) {
// code that depends on `result`
}foo(myHandler);
자 이제 http 요청 결과에 따라 결과가 동작하는 코드를 완성해봅시다.
function foo(callback) {
var httpRequest = new XMLHttpRequest();
httpRequest.onload = function(){ // when the request is loaded
callback(httpRequest.responseText);// we're calling our method };
httpRequest.open('GET', "/echo/json");
httpRequest.send();}
우리는 foo가 AJAX가 성공적으로 완료되었을 때의 액션을 캡쳐할 수 있도록 만들었습니다. 응답의 statue가 200인지를 체크해서 한번 더 체크해줄 수도 있습니다.
var result = foo();
// 결과에 따라 달라지는 코드
foo(function(result) {
// 결과에 따라 달라지는 코드
});
function myHandler(result) {
// code that depends on `result`
}
foo(myHandler);
function foo(callback) {
var httpRequest = new XMLHttpRequest();
httpRequest.onload = function(){ // when the request is loaded
callback(httpRequest.responseText);// we're calling our method
};
httpRequest.open('GET', "/echo/json");
httpRequest.send();
}
반응형
'Basic > Javascript' 카테고리의 다른 글
좋은 OOP(객체지향 프로그래밍)의 10가지 Golden Rules (계속 추가 예정) (0) | 2017.10.31 |
---|---|
[자바스크립트 패턴] ① 리터럴을 이용한 객체 생성 패턴 (0) | 2017.07.04 |
자바스크립트 코딩 컨벤션(스타일 가이드) (2) | 2017.07.03 |
[자바스크립트] 문자 ↔ 숫자 타입 변환 방법 / 성능 분석 (0) | 2017.06.27 |
Javascript setInterval 즉시 실행하는 방법 (1) | 2017.06.15 |