Waarom is mijn asynchrone functie die belofte {& LT; PENDING & GT; } in plaats van een waarde?

Mijn code:

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

En wanneer ik iets als dit probeer uit te voeren:

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

Ik krijg:

Promise { <pending> }

Maar waarom?

Mijn hoofddoel is om Token te krijgen van google.login(data.username, data.password)die een belofte retourneert, in een variabele. En alleen en vervolgens enkele acties voorvorm.


1, Autoriteit 100%

De belofte zal altijd in behandeling zijn zolang de resultaten nog niet zijn opgelost. U moet .thenbeloven met de belofte om de resultaten vast te leggen, ongeacht de belofte (opgelost of nog in behandeling):

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"
})

Waarom is dat?

Beloften zijn alleen voorwaartse richting; Je kunt ze maar één keer oplossen. De opgeloste waarde van een Promisewordt doorgegeven aan de .thenof .catchmethoden.

Details

Volgens de beloften / A + Spec:

De procedure voor belofingsresolutie is een abstracte operatie die neemt als
voer een belofte en een waarde in, die we aanduiden als [[Resolve]](promise,
x). Als x een dan is, probeert het de belofte de toestand van te laten aannemen
x, in de veronderstelling dat x zich op zijn minst enigszins als a . gedraagt
belofte. Anders voldoet het aan de belofte met de waarde x.

Deze behandeling van danables stelt belofte-implementaties in staat om
interoperabel zijn, zolang ze een Promises/A+-compliant dan blootleggen
methode. Het stelt Promises/A+ implementaties ook in staat om te “assimileren”
niet-conforme implementaties met redelijke methoden.

Deze specificatie is een beetje moeilijk te ontleden, dus laten we het opsplitsen. De regel is:

Als de functie in de .then-handler een waarde retourneert, wordt de Promiseopgelost met die waarde. Als de handler nog een Promiseretourneert, wordt de oorspronkelijke Promiseopgelost met de opgeloste waarde van de gekoppelde Promise. De volgende .then-handler bevat altijd de opgeloste waarde van de geketende belofte die is geretourneerd in de vorige .then.

De manier waarop het echt werkt, wordt hieronder in meer detail beschreven:

1. De terugkeer van de functie .thenis de opgeloste waarde van de belofte.

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. Als de functie .theneen Promiseretourneert, wordt de opgeloste waarde van die geketende belofte doorgegeven aan de volgende .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"
  });

Antwoord 2, autoriteit 13%

Ik weet dat deze vraag 2 jaar geleden is gesteld, maar ik loop tegen hetzelfde probleem aan en het antwoord op het probleem is sinds ES2017, dat je gewoon kunt awaitop de retourwaarde van de functie (vanaf nu , werkt alleen in async-functies), zoals:

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

Antwoord 3, autoriteit 2%

De methode thenretourneert een in behandeling zijnde belofte die asynchroon kan worden opgelost door de retourwaarde van een resultaat-handler die is geregistreerd in de aanroep naar then, of kan worden afgewezen door een fout te genereren binnen de handler aangeroepen.

Dus het aanroepen van AuthUserzal de gebruiker niet plotseling synchroon aanmelden, maar een belofte teruggeven waarvan de geregistreerde handlers zullen worden aangeroepen nadat het inloggen is gelukt (of mislukt). Ik zou willen voorstellen om alle login-verwerking te activeren door een then-clausule van de login-belofte. E.G. benoemde functies gebruiken om de volgorde van de stroom te markeren:

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);
}

4

Zie de MDN-sectie op beloftes. Bekijk in het bijzonder het retourtype dan ().

Om in te loggen, moet de gebruikersagent een verzoek aan de server indienen en wachten om een ​​reactie te ontvangen. Aangezien het de uitvoering van uw aanvraag volledig stoppen tijdens een aanvraag Round-trip meestal zorgt voor een slechte gebruikerservaring, praktisch elke JS-functie die u inlogt (of voert een andere vorm van serverinteractie), een belofte, of iets dergelijks , om resultaten asynchroon te leveren.

Nu, merk ook op dat returnuitspraken altijd worden geëvalueerd in de context van de functie die ze verschijnen. Dus wanneer u schreef:

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

De verklaring return token;betekende dat de anonieme functie wordt ingevoerd in then()moet retourneren, niet dat de AuthUserfunctie zou moeten. Wat AuthUserRetourneren is het resultaat van het bellen google.login(username, password).then(callback);, die toevallig een belofte is.

Uiteindelijk uw terugbellen token => { return token; }doet niets; In plaats daarvan moet uw invoer naar then()een functie zijn die het token op de een of andere manier behandelt.


5

Als die situatie gebeurt voor een meerdere waarden zoals een array.

[ 
  Promise { <pending> },
  Promise { <pending> },
  Promise { <pending> },
  Promise { <pending> },
  Promise { <pending> }
]

U kunt Promise.all()Hiermee wordt alle beloften opgelost.

https: //developer.mozilla .org / nl-us / docs / web / javascript / referentie / global_Objects / belofte / alles


6

Ik had eerder hetzelfde probleem, maar mijn situatie was een beetje anders in de front-end. Ik zal het sowieso mijn scenario delen, misschien kan iemand het nuttig vinden.

Ik had een api-aanroep naar /api/user/registerin de frontend met e-mail, wachtwoord en gebruikersnaam als verzoektekst. Bij het indienen van het formulier (registerformulier), wordt een handlerfunctie aangeroepen die de ophaalaanroep naar /api/user/registerinitieert. Ik gebruikte de event.preventDefault()in de beginregel van deze handlerfunctie, alle andere regels, zoals het vormen van de request-body en de fetch-aanroep werd geschreven na de event.preventDefault(). Dit leverde een pending promiseop.

Maar toen ik de code voor het opmaken van de aanvraagtekst boven de event.preventDefault()plaatste, gaf het de echte belofte terug. Zoals dit:

event.preventDefault();
    const data = {
        'email': email,
        'password': password
    }
    fetch(...)
     ...

in plaats van:

    const data = {
            'email': email,
            'password': password
        }
     event.preventDefault();
     fetch(...)
     ...

Antwoord 7

Probeer dit

var number1 = document.getElementById("number1");
var number2 = document.getElementById("number2");
startAsync.addEventListener("click", function() {
    if (number1.value > 0 && number2.value > 0) {
        asyncTest(parseInt(number1.value), parseInt(number2.value)).then(function(result) {
            document.getElementById("promiseResolved").textContent = "promiseResolved: " + result
        });
    } else {
        asyncTest(1, 2).then(function(result) {
            document.getElementById("promiseResolved").textContent = "promiseResolved: " + result
        });
    }
});
async function asyncTest(a, b) {
    return await (a + b);
};
 <button id="startAsync">start Async function</button><br />
  <input type="number" id="number1" /><br />
  <input type="number" id="number2" /><br />
  <span id="promiseResolved"></span><br />

Other episodes