비동기 함수가 값 대신 Promise {<pending>}을 반환하는 이유는 무엇입니까?


128

내 코드 :

let AuthUser = data => {
  return google.login(data.username, data.password).then(token => { return token } )
}

그리고 다음과 같이 실행하려고 할 때 :

let userToken = AuthUser(data)
console.log(userToken)

나는 얻고있다 :

Promise { <pending> }

그런데 왜?

내 주요 목표는 google.login(data.username, data.password)약속을 반환하는 토큰을 변수로 가져 오는 것입니다 . 그리고 나서야 몇 가지 조치를 취할 수 있습니다.


1
@ LoïcFaure-Lacroix,이 기사 참조 : medium.com/@bluepnume/…
Src

에서 LoïcFaure - 라크 모양 @ getFirstUser기능
Src에

그래서 어떻습니까? 약속을 반환하는 함수입니다.
Loïc Faure-Lacroix

1
@ LoïcFaure-Lacroix 그래서이 예제에서도 getFirstUser 함수에서 반환되는 데이터 약속에 액세스하기 위해 사용해야한다는 의미입니까?
Src

이 예에서 유일한 다른 방법은 약속의 결과를 기다리기 위해 현재 컨텍스트의 실행을 중지하는 것으로 확인되는 ES7 구문 "await"를 사용하는 것입니다. 기사를 읽으면 볼 수 있습니다. 그러나 ES7은 아직 거의 지원되지 않기 때문에 그렇습니다. "then"은 거의 그것입니다.
Loïc Faure-Lacroix

답변:


175

약속은 결과가 아직 해결되지 않는 한 항상 보류 중으로 기록됩니다. .then약속 상태 (해결됨 또는 아직 보류 중)에 관계없이 결과를 캡처하려면 약속을 호출해야합니다 .

let AuthUser = function(data) {
  return google.login(data.username, data.password).then(token => { return token } )
}

let userToken = AuthUser(data)
console.log(userToken) // Promise { <pending> }

userToken.then(function(result) {
   console.log(result) // "Some User token"
})

왜 그런 겁니까?

약속은 전진 ​​방향 일뿐입니다. 한 번만 해결할 수 있습니다. a의 확인 된 값은 Promise해당 .then또는 .catch메서드에 전달됩니다 .

세부

Promises / A + 사양에 따르면 :

Promise 해결 절차는 Promise와 값을 입력으로받는 추상 연산으로, [[Resolve]] (promise, x)로 표시됩니다. x가 thenable이면 x가 적어도 약속처럼 행동한다는 가정하에 promise가 x의 상태를 채택하도록 시도합니다. 그렇지 않으면 x 값으로 약속을 이행합니다.

이러한 thenables 처리를 통해 Promise / A + 호환 then 메서드를 노출하는 한 promise 구현이 상호 운용 될 수 있습니다. 또한 Promises / A + 구현이 합리적인 then 메서드로 부적합 구현을 "동화"할 수 있습니다.

이 사양은 파싱하기가 조금 어렵 기 때문에 분석해 보겠습니다. 규칙은 다음과 같습니다.

에서 함수 경우 .then핸들러는 값, 다음 반환 Promise하는 값을 해결합니다. 핸들러가 다른 것을 반환 Promise하면 원래 Promise는 체인의 해결 된 값으로 해결 Promise됩니다. 다음 .then처리기는 항상 이전에서 반환 된 연결 약속의 확인 된 값을 포함합니다 .then.

실제로 작동하는 방식은 아래에 자세히 설명되어 있습니다.

1. .then함수 의 반환은 약속의 해결 된 값이됩니다.

function initPromise() {
  return new Promise(function(res, rej) {
    res("initResolve");
  })
}

initPromise()
  .then(function(result) {
    console.log(result); // "initResolve"
    return "normalReturn";
  })
  .then(function(result) {
    console.log(result); // "normalReturn"
  });

2. .then함수가를 반환하면 Promise연결된 프라 미스의 확인 된 값이 다음으로 전달됩니다 .then.

function initPromise() {
  return new Promise(function(res, rej) {
    res("initResolve");
  })
}

initPromise()
  .then(function(result) {
    console.log(result); // "initResolve"
    return new Promise(function(resolve, reject) {
       setTimeout(function() {
          resolve("secondPromise");
       }, 1000)
    })
  })
  .then(function(result) {
    console.log(result); // "secondPromise"
  });

첫 번째가 작동하지 않습니다. Uncaught SyntaxError: Unexpected token .. 두 번째는 반환이 필요합니다Promise
zamil

@zamil은 두 번째 예제와 같이 함수를 호출해야합니다. 당신은 캔트 .then도하지 않은 기능에. 대답 업데이트
Bamieh

1
영원히 보관할 수 있도록 북마크하고 있습니다. 나는 실제로 프라 미스를 구축하는 방법에 대한 진정으로 명확하고 읽기 쉬운 규칙을 찾기 위해 아주 오랫동안 작업 해 왔습니다. Promises / A + 사양의 인용문은 약속을 스스로 가르치는 것이 PITA 인 이유에 대한 완벽한 예입니다. 또한 레슨 자체를 혼동하지 않는 곳에서 setTimeout이 사용되는 것을 본 유일한 시간이기도합니다. 그리고 훌륭한 참조, 감사합니다.
monsto

21

이 질문이 2 년 전에 요청되었다는 것을 알고 있지만 동일한 문제가 발생했으며 문제에 대한 대답은 ES6 이후로 await다음과 같이 함수가 값을 반환 할 수 있다는 것입니다.

let AuthUser = function(data) {
  return google.login(data.username, data.password).then(token => { return token } )
}

let userToken = await AuthUser(data)
console.log(userToken) // your data

3
은 필요하지 않으며 .then(token => return token)불필요한 통과 일뿐입니다. Google 로그인 호출에 응답하기 만하면됩니다.
Soviut

이 답변은 질문과 관련이 없습니다. 원본 포스터의 문제는 ES6의 async / await와 관련이 없습니다. 이 새로운 구문 설탕이 ECMAScript 2017에 도입되기 전에 약속이 존재했으며 그들은 "내부"에서 약속을 사용했습니다. async / await의 MDN을 참조하십시오 .
시도 - 캐치 마침내

ES8 / Nodejs await의 경우 비동기 함수 외부에서 사용하면 오류가 발생 합니다. 아마도 여기서 더 좋은 예는 AuthUser함수 를 만드는 것입니다 async. 그 다음은 다음으로 끝납니다return await google.login(...);
Jon L.

4

then메서드는에 대한 호출에 등록 된 결과 처리기의 반환 값에 의해 비동기 적으로 해결 then되거나 호출 된 처리기 내부에서 오류를 발생시켜 거부 될 수있는 보류중인 약속을 반환합니다 .

따라서 호출 AuthUser은 사용자를 갑자기 동 기적으로 로그인하지 않고 로그인 성공 (또는 실패) 후에 등록 된 핸들러가 호출 될 promise를 반환합니다. then로그인 약속 의 조항에 따라 모든 로그인 처리를 트리거하는 것이 좋습니다 . 명명 된 함수를 사용하여 흐름 순서를 강조하는 EG :

let AuthUser = data => {   // just the login promise
  return google.login(data.username, data.password);
};

AuthUser(data).then( processLogin).catch(loginFail);

function processLogin( token) {
      // do logged in stuff:
      // enable, initiate, or do things after login
}
function loginFail( err) {
      console.log("login failed: " + err);
}

1

약속 에 대한 MDN 섹션을 참조하십시오 . 특히 then () 의 반환 유형을 살펴보십시오 .

로그인하려면 사용자 에이전트는 서버에 요청을 제출하고 응답을받을 때까지 기다려야합니다. 요청 왕복 동안 응용 프로그램 실행을 완전히 중지하면 일반적으로 사용자 경험이 좋지 않으므로 실제로 로그인하는 (또는 다른 형태의 서버 상호 작용을 수행하는) 모든 JS 함수는 Promise 또는 이와 유사한 것을 사용합니다. , 결과를 비동기 적으로 제공합니다.

이제 return명령문은 항상 나타나는 함수의 컨텍스트에서 평가됩니다. 따라서 다음과 같이 작성했습니다.

let AuthUser = data => {
  return google
    .login(data.username, data.password)
    .then( token => {
      return token;
    });
};

이 명령문 return token;은 전달되는 익명 함수가 then()토큰을 반환해야 한다는 의미가 아니라 토큰을 반환해야 함을 의미했습니다 AuthUser. 무엇 AuthUser반환하면 호출 한 결과입니다 google.login(username, password).then(callback);약속 될 일이있는.

궁극적으로 콜백 token => { return token; }은 아무것도하지 않습니다. 대신 입력 then()은 실제로 어떤 방식 으로든 토큰을 처리하는 함수 여야합니다.


@Src 나는 asker가 동기식 으로 값을 반환 하는 방법을 찾고 있다고 밝히기 전에 내 대답을 작성 했으며 코드 조각에서 추론 할 수있는 것 이상의 개발 환경 또는 언어 버전에 대한 가정을하지 않고 있습니다. ES6을 가정하지만 반드시 ES7은 아닙니다.
Jesse Amano

@AhmadBamieh 좋아, 할 것이다. 나는 문제가 내가 returnnew (ish) 클로저 구문으로 처리되는 방법을 오해했다고 가정하고 있습니다 .
Jesse Amano

2
@AhmadBamieh 어, 나는 실제로 그 부분을 알고 있었기 때문에 그것이 비생산적이라고 주장하는 것과는 반대로 token => { return token; } 아무것도하지 않는다고 주장한 이유 입니다. google.login(username, password).then(token=>{return token;}).then(token=>{return token;})영원히 말할 수는 있지만 Promise토큰으로 해결되는 a 만 반환 할 수 있습니다 google.login(username, password);. 마치 . 왜 이것이 "매우 틀렸다"고 느끼는지 모르겠습니다.
Jesse Amano

1
@AhmadBamieh :이 텍스트에서 무엇이 잘못되었는지 더 구체적으로 말씀해 주시겠습니까? 나는 아무것도 보지 못하고, 그는 return token아마도 OP가 예상대로 작동하지 않는 이유를 설명합니다 .
Bergi

3
@AhmadBamieh : 실제로 오해가 있습니다. 약속 작업이, 문은 그게 얼마나 우리는 세 가지 잘 알고 promise.then(result => { return result; })정확히 동일합니다 promise때문에 메서드 호출이, 아무것도하지 않는 완전히 사실이다 성명 -하고 코드를 단순화하고 가독성을 향상시키기 위해 감소되어야한다.
Bergi

0

귀하의 약속 하여 완료, 보류

userToken.then(function(result){
console.log(result)
})

나머지 코드 뒤에. 이 코드는 .then()약속 을 완료하고 결과 변수 의 최종 결과를 캡처하고 콘솔에 결과를 인쇄하는 것입니다. 결과를 전역 변수에 저장할 수 없습니다. 그 설명이 도움이되기를 바랍니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.