비동기 콜에서 응답을 반환하려면 어떻게 해야 하나요?

함수의 응답/결과를 반환하려면 어떻게 해야 합니까?foo비동기식 요청을 하는 건가요?

콜백에서 값을 반환하고 함수 내의 로컬 변수에 결과를 할당하여 반환하려고 합니다만, 실제로 응답을 반환하는 방법은 없습니다.모두 반환됩니다.undefined또는 변수의 초기값이 무엇이든result이에요.

콜백을 받아들이는 비동기 함수의 예(jQuery 사용)ajax기능):

function foo() {
var result;
$.ajax({
url: '...',
success: function(response) {
 result = response;
 // return response; // <- I tried that one as well
}
});
return result; // It always returns `undefined` } 

Node.js를 사용하는 예:

function foo() {
var result;
fs.readFile("path/to/file", function(err, data) {
result = data;
// return data; // <- I tried that one as well
});
return result; // It always returns `undefined` } 

의 사용 예then약속 블록:

function foo() {
var result;
fetch(url).then(function(response) {
result = response;
// return response; // <- I tried that one as well
});
return result; // It always returns `undefined` } 


질문에 대한 답변



→ 다른 예제를 사용한 비동기 동작에 대한 보다 일반적인 설명은 을 참조하십시오. 함수 내부에서 변수를 수정해도 변경되지 않는 이유는 무엇입니까? – 비동기 코드 참조

→ 문제를 이미 이해한 경우, 아래의 가능한 해결책으로 건너뜁니다.

문제

AjaxA비동기(asynchronous)를 나타냅니다.즉, 요청을 보내는 것(또는 응답을 받는 것)이 일반 실행 흐름에서 제외됩니다.이 예에서는$.ajax즉시 반환하고 다음 문장이 반환됩니다.return result;로 전달된 함수보다 먼저 실행됩니다.success콜백도 호출되었습니다.

다음은 동기 흐름과 비동기 흐름의 차이를 명확하게 하는 유추입니다.

동기

친구에게 전화를 걸어 당신을 위해 무언가를 찾아달라고 부탁한다고 상상해 보세요.비록 시간이 좀 걸릴지 모르지만, 당신은 전화를 기다리며 당신의 친구가 당신에게 필요한 답을 줄 때까지 허공을 응시한다.

「normal」코드를 포함한 함수 콜을 발신해도 같은 현상이 발생합니다.

function findItem() {
var item;
while(item_not_found) {
// search
}
return item; }
var item = findItem();
// Do something with item doSomethingElse(); 

그럼에도 불구하고.findItem실행하는데 오랜 시간이 걸릴 수 있습니다.코드 뒤에 오는 경우var item = findItem();함수가 결과를 반환할 때까지 기다려야 합니다.

비동기

당신은 같은 이유로 친구에게 다시 전화해요.하지만 이번에는 당신이 급하다고 그에게 말하고 그는 당신의 휴대전화로 당신에게 다시 전화해야 합니다.전화를 끊고 집을 나서면 뭐든 할 수 있어친구가 당신에게 다시 전화를 걸면, 당신은 그가 당신에게 준 정보를 다루는 것입니다.

그게 바로 당신이 Ajax 요청을 했을 때 일어나는 일입니다.

findItem(function(item) {
// Do something with the item }); doSomethingElse(); 

응답을 기다리는 대신 즉시 실행이 계속되며 Ajax 콜이 실행된 후 문이 실행됩니다.최종적으로 응답을 얻으려면 응답이 수신된 후 호출되는 함수인 콜백(알림? 콜백?)을 제공합니다.콜백이 호출되기 전에 해당 콜 뒤에 오는 모든 문이 실행됩니다.


솔루션

JavaScript의 비동기적 특성을 수용하십시오!특정 비동기 연산은 동기 연산을 제공하지만(“Ajax”도 제공하지만, 일반적으로 이러한 연산을 사용하는 것은 권장되지 않습니다. 특히 브라우저 컨텍스트에서 그렇습니다.

왜 안 좋은지 물어봐요?

JavaScript는 브라우저의 UI 스레드에서 실행되며 장시간 실행되는 프로세스는 UI를 잠그고 응답하지 않습니다.또한 JavaScript 실행 시간에는 상한이 있으며 브라우저는 실행을 계속할지 여부를 사용자에게 묻습니다.

이로 인해 사용자 환경이 매우 나빠집니다.사용자는 모든 것이 제대로 작동하는지 알 수 없습니다.게다가 접속이 느린 유저에게는, 그 영향이 더 나빠집니다.

다음에서는 서로 구축되어 있는 3가지 솔루션에 대해 설명합니다.

  • 와의 약속(ES2017+, 트랜스필러 또는 재생기를 사용하는 경우 이전 브라우저에서 사용 가능)
  • 콜백(노드에서 널리 사용됨)
  • 와의 약속(ES2015+, 여러 약속 라이브러리 중 하나를 사용하는 경우 이전 브라우저에서 사용 가능)

이 세 가지 모두 현재 브라우저 및 노드 7+에서 사용할 수 있습니다.


ES2017+: 약속

2017년에 출시된 ECMAScript 버전에서는 비동기 함수에 대한 구문 수준 지원이 도입되었습니다.의 도움으로async그리고.await, 「동기식」으로 비동기식으로 쓸 수 있습니다.코드는 아직 비동기이지만 읽기/이해하기 쉽습니다.

async/await약속을 기반으로 구축:async함수는 항상 약속을 반환합니다. await약속을 “해제”하여 약속이 해결된 값을 가져오거나 약속이 거부되면 오류를 발생시킵니다.

중요:사용할 수 있는 것은await안쪽에서async기능 또는 JavaScript 모듈에 있습니다.톱 레벨await모듈 외부에서는 지원되지 않기 때문에 비동기 IIE(즉시 호출된 함수 표현)를 사용하여asynccontext(모듈을 사용하지 않는 경우).

MDN 및 MDN에 대한 자세한 내용은 를 참조하십시오.

다음은 지연 함수를 설명하는 예입니다.findItem()위:

// Using 'superagent' which will return a promise. var superagent = require('superagent')
// This is isn't declared as `async` because it already returns a promise function delay() {
// `delay` returns a promise
return new Promise(function(resolve, reject) {
// Only `delay` is able to resolve or reject the promise
setTimeout(function() {
resolve(42); // After 3 seconds, resolve the promise with value 42
}, 3000);
}); }
async function getAllBooks() {
try {
// GET a list of book IDs of the current user
var bookIDs = await superagent.get('/user/books');
// wait for 3 seconds (just for the sake of this example)
await delay();
// GET information about each book
return superagent.get('/books/ids='+JSON.stringify(bookIDs));
} catch(error) {
// If any of the awaited promises was rejected, this catch block
// would catch the rejection reason
return null;
} }
// Start an IIFE to use `await` at the top level (async function(){
let books = await getAllBooks();
console.log(books); })(); 

현재 브라우저노드 버전 지원async/await또한 재생기(또는 Babel과 같은 재생기를 사용하는 도구)를 사용하여 코드를 ES5로 변환하여 이전 환경을 지원할 수도 있습니다.


함수가 콜백을 받아들이게 하다

콜백이란 함수1이 함수2에 전달되었을 때입니다.Function 2는 Function 1이 준비되면 언제든지 호출할 수 있습니다.비동기 프로세스에서는 비동기 프로세스가 완료될 때마다 콜백이 호출됩니다.보통 결과는 콜백에 전달됩니다.

질문의 예에서는 다음과 같이 할 수 있습니다.foo콜백을 받아들여 로서 사용하다success콜백그래서 이게

var result = foo(); // Code that depends on 'result' 

된다

foo(function(result) {
// Code that depends on 'result' }); 

여기서는 함수를 “인라인”으로 정의했지만 모든 함수 참조를 전달할 수 있습니다.

function myCallback(result) {
// Code that depends on 'result' }
foo(myCallback); 

foo그 자체는 다음과 같이 정의됩니다.

function foo(callback) {
$.ajax({
// ...
success: callback
}); } 

callback전달되는 기능을 참조합니다.foo우리가 그것을 호출하고 전달하면success즉, Ajax 요청이 성공하면$.ajax전화할 것이다callback응답을 콜백에 전달합니다(콜백은 에서 참조할 수 있습니다).result(콜백은 이렇게 정의되어 있기 때문입니다.

콜백에 전달하기 전에 응답을 처리할 수도 있습니다.

function foo(callback) {
$.ajax({
// ...
success: function(response) {
 // For example, filter the response
 callback(filtered_response);
}
}); } 

콜백을 사용하여 코드를 작성하는 것은 보기보다 쉽습니다.결국 브라우저의 JavaScript는 이벤트 중심(DOM 이벤트)입니다.Ajax 응답 수신은 이벤트일 뿐입니다.서드파티 코드로 작업해야 할 경우 어려움이 발생할 수 있지만 대부분의 문제는 애플리케이션 흐름에서 생각만 하면 해결할 수 있습니다.


ES2015+: 그 때()와의 약속

Promise API는 ECMAScript 6(ES2015)의 신기능이지만 브라우저 지원은 이미 양호합니다.표준 Promise API를 구현하고 비동기 함수(예: Bluebird)의 사용과 구성을 용이하게 하는 추가 방법을 제공하는 라이브러리도 많이 있습니다.

약속은 미래의 가치를 담는 용기입니다.약속이 값을 수신(해결됨)하거나 취소(거부됨)되면 이 값에 액세스하려는 모든 “청취자”에게 알립니다.

일반 콜백에 비해 장점은 코드를 분리할 수 있고 구성하기 쉽다는 것입니다.

다음은 약속을 사용하는 예입니다.

function delay() {
// `delay` returns a promise
return new Promise(function(resolve, reject) {
// Only `delay` is able to resolve or reject the promise
setTimeout(function() {
resolve(42); // After 3 seconds, resolve the promise with value 42
}, 3000);
}); }
delay()
.then(function(v) { // `delay` returns a promise
console.log(v); // Log the value once it is resolved
})
.catch(function(v) {
// Or do something else if it is rejected
// (it would not happen in this example, since `reject` is not called).
});
.as-console-wrapper { max-height: 100% !important; top: 0; }

Ajax 콜에 적용하면 다음과 같은 약속을 사용할 수 있습니다.

function ajax(url) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
resolve(this.responseText);
};
xhr.onerror = reject;
xhr.open('GET', url);
xhr.send();
}); }
ajax("https://jsonplaceholder.typicode.com/todos/1")
.then(function(result) {
console.log(result); // Code depending on result
})
.catch(function() {
// An error occurred
});
.as-console-wrapper { max-height: 100% !important; top: 0; }

이 약속의 장점을 모두 설명하는 것은 이 답변의 범위를 벗어나지만, 새로운 코드를 작성할 경우에는 진지하게 검토해야 합니다.코드를 매우 추상화하고 분리할 수 있습니다.

약속에 대한 자세한 내용은 HTML5 rocks – JavaScript Promises입니다.

참고: jQuery의 지연 객체

지연 개체는 jQuery가 약속(Promise API가 표준화되기 전)을 커스텀으로 구현한 것입니다.이들은 약속과 거의 비슷하게 행동하지만 약간 다른 API를 노출합니다.

jQuery의 모든 Ajax 메서드는 이미 함수에서 반환할 수 있는 “지연 객체”(실제로 지연된 객체의 약속)를 반환합니다.

function ajax() {
return $.ajax(...); }
ajax().done(function(result) {
// Code depending on result }).fail(function() {
// An error occurred }); 

참고: Promise gotchas

약속과 지연 객체는 미래 가치를 위한 컨테이너일 뿐 값 자체는 아닙니다.예를 들어 다음과 같은 기능이 있다고 가정합니다.

function checkPassword() {
return $.ajax({
url: '/password',
data: {
 username: $('#username').val(),
 password: $('#password').val()
},
type: 'POST',
dataType: 'json'
}); }
if (checkPassword()) {
// Tell the user they're logged in } 

이 코드는 위의 비동기 문제를 오해하고 있습니다.구체적으로는$.ajax()서버에서 ‘/password’ 페이지를 확인하는 동안 코드가 동결되지 않습니다. 서버는 요청을 전송하고 대기하는 동안 서버의 응답이 아닌 jQuery Ajax Delferred 개체를 즉시 반환합니다.즉,if문은 항상 이 Deferred 객체를 다음과 같이 처리합니다.true사용자가 로그인한 것처럼 진행합니다.좋지 않습니다.

그러나 수정은 간단합니다.

checkPassword() .done(function(r) {
if (r) {
// Tell the user they're logged in
} else {
// Tell the user their password was bad
} }) .fail(function(x) {
// Tell the user something bad happened }); 

권장 안 함:동기 “Ajax” 호출

앞서 언급했듯이, 일부 비동기 작업에는 동기식 작업이 있습니다.이러한 서비스를 사용하는 것을 권장하지는 않지만, 완벽성을 위해 동기식 콜을 수행하는 방법은 다음과 같습니다.

jQuery 없음

개체를 직접 사용하는 경우,false의 세 번째 인수로서

j쿼리

jQuery를 사용하는 경우,async할 수 있는 선택권false이 옵션은 jQuery 1.8 이후 권장되지 않습니다.그 후, 다음의 어느쪽인가를 사용할 수 있습니다.success콜백 또는 액세스responseTextjqXHR 객체의 속성:

function foo() {
var jqXHR = $.ajax({
//...
async: false
});
return jqXHR.responseText; } 

다음과 같은 다른 jQuery Ajax 메서드를 사용하는 경우$.get,$.getJSON, 등으로 변경해야 합니다.$.ajax(설정 파라미터를 전달할 수 있는 것은$.ajax).

조심해!동기 JSONP 요구는 할 수 없습니다.JSONP는 본질적으로 항상 비동기적입니다(이 옵션을 고려하지 않아도 되는 또 하나의 이유).




코드에서 jQuery를 사용하지 않는 경우 이 답변은 다음과 같습니다.

코드는 다음과 같은 것이어야 합니다.

function foo() {
var httpRequest = new XMLHttpRequest();
httpRequest.open('GET', "/echo/json");
httpRequest.send();
return httpRequest.responseText; }
var result = foo(); // Always ends up being 'undefined' 

Felix Kling은 AJAX를 위해 jQuery를 사용하는 사람들을 위해 훌륭한 답변을 작성했지만, 저는 그렇지 않은 사람들을 위해 대안을 제공하기로 결정했습니다.

(새로운 API, Angular 또는 아래에 다른 답변을 추가했습니다.)


당면한 과제

이것은 다른 답변의 “문제 설명”을 간략하게 요약한 것입니다. 이 글을 읽고 잘 모르겠으면 읽어보세요.

AJAX의 A비동기(asynchronous)를 나타냅니다.즉, 요청을 보내는 것(또는 응답을 받는 것)이 일반 실행 흐름에서 제외됩니다.이 예에서는 가 즉시 반환하고 다음 문이 반환됩니다.return result;로 전달된 함수보다 먼저 실행됩니다.success콜백도 호출되었습니다.

즉, 반환할 때 정의한 수신기가 아직 실행되지 않았음을 의미합니다. 즉, 반환할 값이 정의되지 않았습니다.

다음은 간단한 비유입니다.

function getFive(){
var a;
setTimeout(function(){
a=5;
},10);
return a; } 

(피들)

가치a반환된 것은undefined그 이후a=5부품이 아직 실행되지 않았습니다.AJAX는 다음과 같이 동작합니다.서버가 브라우저에 값을 알리기 전에 값을 반환하는 것입니다.

이 문제에 대한 가능한 해결책 중 하나는 계산 완료 시 프로그램에 대해 다시 코드화하는 것입니다.

function onComplete(a){ // When the code completes, do this
alert(a); }
function getFive(whenDone){
var a;
setTimeout(function(){
a=5;
whenDone(a);
},10); } 

이를 CPS라고 합니다.기본적으로, 우리는 지나가고 있다.getFive이벤트가 완료되었을 때 실행하는 액션은 이벤트가 완료되었을 때(AJAX 콜, 이 경우 타임아웃 등)에 대응하는 방법을 코드에 지시합니다.

사용 방법은 다음과 같습니다.

getFive(onComplete); 

화면에 “5라고 경고할 거야

생각할 수 있는 해결책

이 문제를 해결하려면 기본적으로 두 가지 방법이 있습니다.

  1. AJAX 콜을 동기합니다(SJAX라고 합니다).
  2. 콜백과 올바르게 동작하도록 코드를 재구성합니다.

1. 동기 AJAX – 하지 마!!

동기 AJAX는 하지 마세요!펠릭스의 대답은 왜 그것이 나쁜 생각인지에 대한 설득력 있는 주장을 제기한다.요약하면 서버가 응답을 반환하고 매우 나쁜 사용자 환경을 만들 때까지 사용자의 브라우저를 정지합니다.MDN에서 얻은 또 하나의 간단한 개요는 다음과 같습니다.

XMLHttpRequest는 동기 통신과 비동기 통신을 모두 지원합니다.그러나 일반적으로 성능상의 이유로 동기 요구보다 비동기 요구를 선호해야 합니다.

즉, 동기 요구는 코드 실행을 차단합니다…이것은 심각한 문제를 일으킬 수 있습니다…

해야 한다면 깃발을 넘길 수 있다.방법은 다음과 같습니다.

var request = new XMLHttpRequest(); request.open('GET', 'yourURL', false);
// `false` makes the request synchronous request.send(null);
if (request.status === 200) {// That's HTTP for 'ok'
console.log(request.responseText); } 

2. 구조 변경 코드

함수가 콜백을 받아들이도록 하겠습니다.예제 코드에서는foo콜백을 받아들이도록 할 수 있습니다.우리는 우리의 코드에 어떻게 반응해야 하는지 알려줄게요.foo완료됩니다.

그래서:

var result = foo(); // Code that depends on `result` goes here 

이하가 됩니다.

foo(function(result) {
// Code that depends on `result` }); 

여기서는 익명 함수를 전달했지만 기존 함수에 대한 참조를 쉽게 전달하여 다음과 같이 만들 수 있습니다.

function myHandler(result) {
// Code that depends on `result` } foo(myHandler); 

이러한 종류의 콜백 설계가 어떻게 이루어지는지에 대한 자세한 내용은 Felix의 답변을 참조하십시오.

이제 foo 자체를 정의하여 그에 따라 동작하도록 하겠습니다.

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가 정상적으로 완료되었을 때 실행할 액션을 받아들이도록 했습니다.응답 상태가 200이 아닌지 확인하고 그에 따라 처리함으로써 이 기능을 더욱 확장할 수 있습니다(장애 핸들러 작성 등).사실상 그것은 우리의 문제를 해결하고 있다.

그래도 이해하기 어렵다면 MDN에서 AJAX 시작 가이드를 읽어보십시오.




XMLHttpRequest 2(우선 Benjamin Gruenbaum과 Felix Kling의 답변을 읽습니다)

jQuery를 사용하지 않고 최신 브라우저 및 모바일브라우저에서도 동작하는 짧은 XMLHttpRequest 2를 원한다면 다음과 같이 사용하는 것이 좋습니다.

function ajax(a, b, c){ // URL, callback, just a placeholder
c = new XMLHttpRequest;
c.open('GET', a);
c.onload = b;
c.send() } 

보다시피:

  1. 나열된 다른 모든 기능보다 짧습니다.
  2. 콜백은 직접 설정됩니다(따라서 불필요한 닫힘은 없습니다).
  3. 새로운 부하를 사용합니다(ready state & status를 확인할 필요가 없습니다).
  4. XMLHttpRequest 1을 짜증나게 하는 다른 상황도 기억나지 않습니다.

이 Ajax 콜의 응답을 취득하는 방법에는 다음 2가지가 있습니다(XMLHttpRequest var name을 사용하여3가지).

가장 심플한 것:

this.response 

아니면 어떤 이유로든 당신이bind()클래스 콜백:

e.target.response 

예:

function callback(e){
console.log(this.response); } ajax('URL', callback); 

또는 (상기의 어나니머스 함수는 항상 문제가 됩니다)

ajax('URL', function(e){console.log(this.response)}); 

쉬운 일은 없어.

일부에서는 onready state change 또는 XMLHttpRequest 변수명을 사용하는 것이 좋다고 말할 수 있습니다.틀렸어.

XMLHttpRequest 고급 기능을 확인합니다.

모든 *현대 브라우저를 지원했습니다.XMLHttpRequest 2가 작성된 이후 이 방법을 사용하고 있기 때문에 확인할 수 있습니다.어떤 브라우저에서도 문제가 발생한 적이 없습니다.

onready state change는 상태2의 헤더를 취득하는 경우에만 도움이 됩니다.

사용방법XMLHttpRequestvariable name은 onload/oready statechange closure 내에서 콜백을 실행해야 하는 또 하나의 큰 오류입니다.그렇지 않으면 콜백이 손실됩니다.


POST 및 FormData를 사용하여 보다 복잡한 기능을 원하는 경우 이 기능을 쉽게 확장할 수 있습니다.

function x(a, b, e, d, c){ // URL, callback, method, formdata or {key:val},placeholder
c = new XMLHttpRequest;
c.open(e
'get', a);
c.onload = b;
c.send(d
null) } 

또…매우 짧은 기능이지만 GET과 POST가 가능합니다.

사용 예:

x(url, callback); // By default it's GET so no need to set x(url, callback, 'post', {'key': 'val'}); // No need to set POST data 

또는 전체 양식 요소를 전달합니다(document.getElementsByTagName('form')[0]):

var fd = new FormData(form); x(url, callback, 'post', fd); 

또는 몇 가지 사용자 지정 값을 설정합니다.

var fd = new FormData(); fd.append('key', 'val') x(url, callback, 'post', fd); 

보시다시피 저는 싱크를 구현하지 않았습니다.나쁜 짓이에요

그렇다고는 해도…쉬운 방법으로 하는 게 어때?


코멘트에 기재되어 있듯이, 에러&동기의 사용은, 회답의 요점을 완전히 무너뜨립니다.Ajax를 올바르게 사용하는 간단한 방법은 무엇입니까?

에러 핸들러

function x(a, b, e, d, c){ // URL, callback, method, formdata or {key:val}, placeholder
c = new XMLHttpRequest;
c.open(e
'get', a);
c.onload = b;
c.onerror = error;
c.send(d
null) }
function error(e){
console.log('--Error--', this.type);
console.log('this: ', this);
console.log('Event: ', e) } function displayAjax(e){
console.log(e, this); } x('WRONGURL', displayAjax); 

위의 스크립트에서는 에러 핸들러가 스태틱하게 정의되어 있기 때문에 기능에 영향을 주지 않습니다.에러 핸들러는, 다른 기능에도 사용할 수 있습니다.

그러나 실제로 오류를 해결하려면 잘못된 URL을 쓰는 방법밖에 없습니다.이 경우 모든 브라우저가 오류를 발생시킵니다.

오류 핸들러는 커스텀헤더를 설정하거나 responseType을 blob 어레이 버퍼로 설정하거나 하는 경우에 도움이 될 수 있습니다.

방법으로서 「POSTAPAP」를 패스해도, 에러는 발생하지 않습니다.

fdggdgilfghfldj를 폼 데이터로 전달해도 오류가 발생하지 않습니다.

첫 번째 경우 에러는 에러입니다.displayAjax()아래this.statusText~하듯이Method not Allowed.

두 번째 케이스에서는, 간단하게 동작합니다.올바른 포스트 데이터를 전달했는지 서버 측에서 확인해야 합니다.

크로스 도메인이 허용되지 않으면 오류가 자동으로 발생합니다.

에러 응답에는, 에러 코드는 없습니다.

이 밖에 없습니다.this.type에러로 설정되어 있습니다.

에러를 전혀 제어할 수 없는데 에러 핸들러를 추가하는 이유는 무엇입니까?대부분의 오류는 콜백 함수로 반환됩니다.displayAjax().

따라서 URL을 올바르게 복사하여 붙여넣을 수 있다면 오류 체크를 할 필요가 없습니다.😉

PS: 첫 번째 테스트로 x(‘x’, displayAjax…)라고 썼더니 완전히 반응이…? 그래서 HTML이 있는 폴더를 확인해보니 ‘x.xml’이라는 파일이 있었습니다. 따라서 파일 확장자를 잊어버린 경우에도 XMLHttpRequest 2 WIL FIND IT가 실행됩니다.나는 LOL’d


동기화된 파일 읽기

그러지마세요.

브라우저를 잠시 차단하려면 큰 파일을 로드하십시오..txt파일 동기

function omg(a, c){ // URL
c = new XMLHttpRequest;
c.open('GET', a, true);
c.send();
return c; // Or c.response } 

이제 할 수 있다

 var res = omg('thisIsGonnaBlockThePage.txt'); 

비동기적인 방법으로 이것을 실행하는 다른 방법은 없습니다.(set Timeout 루프를 사용하면…진지하게요?)

또 다른 포인트는…API나 자신의 목록 파일 또는 요청마다 항상 다른 함수를 사용하는 경우…

항상 같은 XML/JSON 또는 필요한 기능을 로드하는 페이지가 있는 경우에만 해당됩니다.이 경우 Ajax 함수를 약간 수정하고 b를 특수 함수로 바꿉니다.


위의 기능은 기본적인 용도로 사용됩니다.

기능을 확장하려면…

네, 가능합니다.

저는 많은 API를 사용하고 있으며, 모든 HTML 페이지에 통합되는 첫 번째 함수 중 하나는 이 답변의 첫 번째 Ajax 함수이며, GET 전용입니다.

그러나 XMLHttpRequest 2에서는 많은 작업을 수행할 수 있습니다.

다운로드 매니저(레줌, 파일 리더, 파일 시스템 양쪽 범위 사용), 캔버스를 사용하여 다양한 이미지 리사이저를 변환하고 웹 SQL 데이터베이스를 base64 이미지로 채우는 등…

단, 이 경우 그 목적으로만 함수를 생성해야 합니다.때로는 BLOB, 어레이 버퍼가 필요합니다.헤더를 설정하거나 mimtype을 덮어쓸 수 있습니다.그리고 그 밖에도…

하지만 여기서 문제는 어떻게 아약스의 답변을…(간단한 방법을 추가했습니다.)




만약 당신이 약속을 사용한다면, 이 답은 당신을 위한 것입니다.

즉, AngularJS, jQuery(지연), 네이티브 XHR의 대체(페치), Ember.js, Backbone.js의 저장 또는 약속을 반환하는 Node.js 라이브러리를 의미합니다.

코드는 다음과 같은 것이어야 합니다.

function foo() {
var data;
// Or $.get(...).then, or request(...).then, or query(...).then
fetch("/echo/json").then(function(response){
data = response.json();
});
return data; }
var result = foo(); // 'result' is always undefined no matter what. 

Felix Kling은 Ajax의 콜백과 함께 jQuery를 사용하는 사람들을 위한 답변을 잘 작성했습니다.네이티브 XHR에 대한 답이 있습니다.이 답변은 프런트엔드 또는 백엔드에서의 일반적인 약속 사용에 대한 것입니다.


핵심 문제

브라우저 및 Node.js/io.js를 사용하는 서버상의 JavaScript 동시성 모델은 비동기적이며 반응적입니다.

약속을 반환하는 메서드를 호출할 때마다then핸들러는 항상 비동기적으로 실행됩니다.즉, 핸들러에 없는 아래의 코드 다음에 실행됩니다..then핸들러

이 말은 당신이 돌아올 때datathen정의한 핸들러가 아직 실행되지 않았습니다.이는 반환하는 값이 시간 내에 올바른 값으로 설정되지 않았음을 의미합니다.

이 문제에 대한 간단한 유추는 다음과 같습니다.


function getFive(){
var data;
setTimeout(function(){ // Set a timer for one second in the future
data = 5; // After a second, do this
}, 1000);
return data;
}
document.body.innerHTML = getFive(); // `undefined` here and not 5

가치dataundefined그 이후data = 5부품이 아직 실행되지 않았습니다.1초 안에 실행될 가능성이 높지만 반환된 값과 무관합니다.

작업이 아직 수행되지 않았으므로(Ajax, 서버 호출, I/O 및 타이머) 요청이 해당 값을 코드에 알리기 전에 값을 반환합니다.

이 문제에 대한 가능한 해결책 중 하나는 계산 완료 시 프로그램을 어떻게 해야 하는지 다시 코드화하는 것입니다.약속은 본질적으로 시간적(시간에 민감함)이므로 이를 능동적으로 가능하게 합니다.

약속에 대한 빠른 재점검

약속은 시간의 경과에 따른 가치입니다.약속은 위엄이 있다.이들은 값 없이 보류 상태로 시작하여 다음과 같이 처리될 수 있습니다.

  • 계산이 성공적으로 완료되었음을 의미합니다.
  • rejected는 계산이 실패했음을 의미합니다.

약속은 상태를 한 번만 바꿀 수 있으며 그 후에는 항상 같은 상태를 유지할 수 있습니다.첨부할 수 있습니다.then값을 추출하여 오류를 처리할 것을 약속합니다. then핸들러를 사용하면, 의 체인을 할 수 있습니다.약속은 약속을 반환하는 API를 사용하여 생성됩니다.예를 들어, 보다 현대적인 Ajax 교체fetch또는 jQuery의$.get약속을 이행하다

전화할 때.then약속에 따라 무엇인가를 반환한다 – 우리는 가공된 가치에 대한 약속을 받는다.한 번 더 약속을 지키면 놀라운 것을 얻을 수 있겠지만, 인내하자.

약속과 함께

위의 문제를 공약으로 어떻게 해결할 수 있을지 지켜보자.먼저 Promise 생성자를 사용하여 지연 함수를 생성하여 위에서 약속 상태에 대한 이해를 보여 줍니다.

function delay(ms){ // Takes amount of milliseconds
// Returns a new promise
return new Promise(function(resolve, reject){
setTimeout(function(){ // When the time is up,
 resolve(); // change the promise to the fulfilled state
}, ms);
}); } 

set Timeout을 약속을 사용하도록 변환한 후에는then계산하기 위해서:

function delay(ms){ // Takes amount of milliseconds
// Returns a new promise
return new Promise(function(resolve, reject){
setTimeout(function(){ // When the time is up,
resolve(); // change the promise to the fulfilled state
}, ms);
}); }
function getFive(){
// We're RETURNING the promise. Remember, a promise is a wrapper over our value
return delay(100).then(function(){ // When the promise is ready,
return 5; // return the value 5. Promises are all about return values
}) } // We _have_ to wrap it like this in the call site, and we can't access the plain value getFive().then(function(five){
document.body.innerHTML = five; });

기본적으로 동시성 모델 때문에 할 수 없는 을 반환하는 대신 래핑을 해제할 수 있는 값의 래퍼를 반환하는 것입니다.then상자 같은 걸로 열 수 있어요.then.

이것을 적용하다

이는 원래 API 호출과 동일하게 다음과 같은 작업을 수행할 수 있습니다.

function foo() {
// RETURN the promise
return fetch("/echo/json").then(function(response){
return response.json(); // Process it inside the `then`
}); }
foo().then(function(response){
// Access the value inside the `then` }) 

이것도 잘 되는군요.이미 비동기 호출에서 값을 반환할 수는 없지만 약속을 사용하여 처리를 수행할 수 있습니다.이것으로 비동기 콜에서 응답을 반환하는 방법을 알게 되었습니다.

ES2015(ES6)

ES6는 중간에 복귀했다가 다시 원래 위치로 복귀할 수 있는 발전기를 도입한다.이것은 일반적으로 다음과 같은 시퀀스에 유용합니다.

function* foo(){ // Notice the star. This is ES6, so new browsers, Nodes.js, and io.js only
yield 1;
yield 2;
while(true) yield 3; } 

시퀀스에 걸쳐 반복기를 반환하는 함수입니다.1,2,3,3,3,3,....반복할 수 있습니다.이것은 그 자체로 흥미롭고 많은 가능성을 열어주는 반면, 한 가지 특별한 사례가 있다.

우리가 생성하는 시퀀스가 숫자가 아닌 일련의 동작일 경우, 우리는 동작이 발생할 때마다 기능을 일시 중지하고 기능을 재개하기 전에 기다릴 수 있습니다.그래서 우리는 일련의 숫자 대신 일련의 미래 가치, 즉 약속들이 필요합니다.

이것은 다소 까다롭지만 매우 강력한 트릭입니다. 동기식으로 비동기 코드를 작성합시다.당신을 위해 이것을 해주는 “달리는 사람”이 몇 명 있습니다.1행은 짧은 코드 몇 줄이지만 이 답변의 범위를 벗어납니다.나는 블루버드를 사용할 것이다.Promise.coroutine여기, 하지만 다른 포장지들도 있어요co또는Q.async.

var foo = coroutine(function*(){
var data = yield fetch("/echo/json"); // Notice the yield
// The code here only executes _after_ the request is done
return data.json(); // 'data' is defined }); 

이 메서드는 약속 자체를 반환하며 다른 코루틴에서 소비할 수 있습니다.예를 들어 다음과 같습니다.

var main = coroutine(function*(){
var bar = yield foo(); // Wait our earlier coroutine. It returns a promise
// The server call is done here, and the code below executes when done
var baz = yield fetch("/api/users/" + bar.userid); // Depends on foo's result
console.log(baz); // Runs after both requests are done }); main(); 

ES2016 (ES7)

ES7에서는 이것이 더욱 표준화되어 있습니다.지금 몇 가지 제안이 있지만, 그 모든 제안에서 당신은 할 수 있습니다.await약속.이는 위의 ES6 제안에서는 ‘설탕'(nicer 구문)을 추가했을 뿐입니다.async그리고.await키워드를 지정합니다.위의 예를 제시하겠습니다.

async function foo(){
var data = await fetch("/echo/json"); // Notice the await
// code here only executes _after_ the request is done
return data.json(); // 'data' is defined } 

그대로 약속을 반환합니다. : )




Ajax를 잘못 사용하고 있습니다.아이디어는 데이터를 반환하는 것이 아니라 데이터를 처리하는 콜백 함수라고 불리는 함수에 데이터를 넘겨주는 것입니다.

즉, 다음과 같습니다.

function handleData( responseData ) {
// Do what you want with the data
console.log(responseData); }
$.ajax({
url: "hi.php",
...
success: function ( data, status, XHR ) {
handleData(data);
} }); 

송신 핸들러에 아무것도 반환하지 않습니다.대신 데이터를 전달하거나 성공 함수 내에서 원하는 작업을 직접 수행해야 합니다.