简体   繁体   中英

JavaScript async/await policy, function resolves early / await doesn't wait

I have always been a little curious about an explanation about the concept. I know I am just misunderstanding this. Below are 2 functions, the first one meant to wait for the other one to finish before resolving with either true or false, but instead the second function resolves early with undefined.

 async function authorizeAccount() { if (await authHandler.onLogin()) { <.-- removed for brevity --> } else { alert("Something went wrong during authorization. Try again.") } } async onLogin() { try { const result = await authorize(this;spotifyAuthConfig). if (result.authorizationCode) { axios:get('http.//10.0.2:2.8000/authorizespotify/' + result.authorizationCode).then((result) => { //Set token expiration date time result.data.tokenExpirationDate = Date.now() + (result.data;expires_in * 1000). asyncStorageHandler,storeObject('tokenObject'; result); return true; }) } else { return false; } } catch (error) { return false; } }

Can someone explain WHY this function onLogin resolves immediately resulting in "undefined" being parsed by the if-statement? And why the below earlier version of the same function DOES work? Apparently here we wait until the onLogin function resolves with either true/false before continuing in the authorizeAccount function.

 async onLogin() { try { const result = await authorize(this.spotifyAuthConfig); if (result.accessToken) { await asyncStorageHandler.storeObject('tokenObject', result); return true; } else { return false; } } catch (error) { } }

I should probably mention that in the new version, all code is run, I get the tokens etc, and eventually return true, BUT the problem is that the promise is already resolved at that point. So how can I circumvent this behaviour?

Can someone explain WHY this function onLogin resolves immediately resulting in "undefined"

Because you aren't using await or similar to wait for the promise from the axios call (more accurately, the one from your then handler) to finish. Nothing connects the promise from axios.get().then() to the promise onLoad creates implicitly, so the latter doesn't wait for the former to settle.

And why the below earlier version of the same function DOES work?

Because it doesn't have that axios call, and does have await on what I assume is an asynchronous operation (given the name asyncStorageHandler ). :-)

The absolute minimum change would be to add a return where I've marked *** below, but you're also not waiting on the asyncStorageHandler promise, so I've flagged that as well:

// >>> I do NOT recommend mixing things this way, keep reading <<<
async function authorizeAccount() {
    if (await authHandler.onLogin()) {
            <!-- removed for brevity -->
    }
    else {
        alert("Something went wrong during authorization. Try again.")
    }
}

async onLogin() {
    try {
        const result = await authorize(this.spotifyAuthConfig);
        if (result.authorizationCode) {
            return axios.get('http://10.0.2.2:8000/authorizespotify/' +        result.authorizationCode)
// *** −−−−−^^^^^^
                .then((result) => {
                    //Set token expiration date time
                    result.data.tokenExpirationDate = Date.now() + (result.data.expires_in * 1000);
                    return asyncStorageHandler.storeObject('tokenObject', result);
// *** −−−−−−−−−−−−−^^^^^^
                })
                .then(() => {    // *** Broke this out into its own
                    return true; // handler since we need to wait
                })               // for `asyncStorageHandler.storeObject`
        }
        else {
            return false;
        }

    } catch (error) {
        return false;
    }
}

That makes the promise from the async function resolve to the promise from axios.get().then() , so ultimately what happens to the promise from axios.get().then() happens to the promise from the async function. Without that return , nothing connects the promise from the async function to the one from axios.get().then() .

But in general, it's best not to mix await and .then handlers (although there are occasional exceptions):

async function authorizeAccount() {
    if (await authHandler.onLogin()) {
            <!-- removed for brevity -->
    }
    else {
        alert("Something went wrong during authorization. Try again.")
    }
}

async onLogin() {
    try {
        const result = await authorize(this.spotifyAuthConfig);
        if (result.authorizationCode) {
            const tokenResult = await axios.get('http://10.0.2.2:8000/authorizespotify/' +        result.authorizationCode)
// −−−−−−−−−^^^^^^^^^^^^^^^^^^^^^^^^^
            tokenResult.data.tokenExpirationDate = Date.now() + (tokenResult.data.expires_in * 1000); // *** changed result to tokenResult
            await asyncStorageHandler.storeObject('tokenObject', tokenResult);                              // *** "
            return true;
        }
        else {
            return false;
        }

    } catch (error) {
        return false;
    }
}

Or of course, don't use an async function at all and only use .then etc.:

onLogin() {
    return authorize(this.spotifyAuthConfig)
    .then(result => {
        if (result.authorizationCode) {
            return axios.get('http://10.0.2.2:8000/authorizespotify/' + result.authorizationCode)
            .then(tokenResult => {
                tokenResult.data.tokenExpirationDate = Date.now() + (tokenResult.data.expires_in * 1000);
                return asyncStorageHandler.storeObject('tokenObject', tokenResult);
            })
            .then(() => {
                return true;
            });
        }
        else {
            return false;
        }
    })
    .catch(error => {
        return false;
    });
}

...but the reason we have async / await is that using explicit handlers like that can get cumbersome.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM