2
votes

Alexa répond avant que les données ne soient renvoyées

Je suis nouveau dans les promesses, async / await, et Alexa / lambda, alors soyez indulgents avec moi.

Ma fonction est de retour avant que les données ne soient renvoyées. J'ai eu un problème similaire où j'obtenais une erreur, mais j'ai depuis modifié un peu ma fonction et donc posé une nouvelle question. Je n'obtiens plus d'erreur, mais mes données sont renvoyées en premier, puis la promesse s'exécute.

J'ai essayé de réécrire la promesse / fonction après avoir lu beaucoup, beaucoup de SO, forums de développeurs google et amazon. Rien ne semble fonctionner pour moi.

const IntentRequest = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'IntentRequest';
    },
    async handle(handlerInput) {
        const { requestEnvelope, serviceClientFactory, responseBuilder } = handlerInput;
        let responseData, promise;

         checkAuthenticationStatus(handlerInput,function(json){
            console.log('waited!')
            if(json.error) {
                return handlerInput.responseBuilder.speak(messages.NO_ACCESS).withSimpleCard('Unauthorized Request', messages.NO_ACCESS).getResponse();
            } else if(json.noerror && json.noerror.okay == 'true'){
                console.log('starting to get intent data')
                const url = new URL(json.noerror.okay.path);
                promise = new Promise((resolve, reject) => { 
                    console.log('start promise')
                   return httpsGetIntent(handlerInput, url).then((resultData) => {
                        console.log(resultData)
                        responseData = resultData;
                        resolve(responseData)
                        console.log('inside promise, no error, prior to return data')
                    })

            }).then((result) => { console.log('result', result)})
                return handlerInput.responseBuilder.speak('Test').getResponse();
            }

        });
        console.log('response data', responseData)

        let result = await promise;
        return result;

    },
};

Parmi mes nombreux console.logs () ajoutés pour le débogage, ils s'affichent comme suit: - 'données de réponse' - 'attendu!' - 'commencer à obtenir des données d'intention' - 'promesse de départ' - resultData - 'promesse intérieure, pas d'erreur, avant de renvoyer les données'


2 commentaires

Comme écrit, return handlerInput.responseBuilder.speak ('Test'). GetResponse (); n'est pas dans un callback .then, malgré l'indentation qui le fait apparaître autrement. Il y a aussi d'autres choses à corriger.


Merci @ Roamer-1888! En fait, j'ai résolu ce problème hier soir et je suis sur le point de publier ma réponse.


3 Réponses :


0
votes

Bien que ce ne soit pas complètement détaillé (je dois aborder la partie de la gestion des erreurs), je voulais partager ma solution ici au cas où quelqu'un tomberait sur ce post et aurait besoin d'aide.

J'ai déplacé la promesse en dehors de la fonction checkAuthentication et renvoyé les données lors de son traitement. J'ai ensuite enchaîné la promesse avec .then () et lui ai transmis les données renvoyées, et j'ai invité Alexa à parler.

const IntentRequest = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'IntentRequest';
    },
    async handle(handlerInput) {
        const { requestEnvelope, serviceClientFactory, responseBuilder } = handlerInput;
        let responseData, promise;
        return new Promise((resolve, reject) => {
            checkAuthenticationStatus(handlerInput, async function(json) {
                if (json.error) {
                    return handlerInput.responseBuilder.speak(messages.NO_ACCESS).withSimpleCard('Unauthorized Request', messages.NO_ACCESS).getResponse();
                } else if (json.noerror && json.noerror.okay == 'true') {
                    const url = new URL(json.noerror.okay.path);
                    let resultD = await httpsGetIntent(handlerInput, url, function(resultData) {
                        if (resultData) {
                            return resolve(resultData);
                        } else {
                            return resolve(handlerInput.responseBuilder.speak('False Test').getResponse());
                        }
                    })

                }
            })

        }).then((data) => {
            return handlerInput.responseBuilder.speak(data.response.outputSpeech.text).getResponse();
        });
    },
};


2 commentaires

httpsGetIntent () est un peu déroutant. D'une part, vous l'attendez (indiquant qu'il renvoie Promise) tandis que d'autre part, il accepte un rappel. En règle générale, une fonction (ou tout appel particulier) présente un comportement ou un autre.


@ Roamer-1888 J'apprécie l'aide! Je ne comprends pas totalement async / await et je faisais référence à d'autres exemples d'Alexa



0
votes

Presque_Ashleigh, basé sur votre propre réponse, quelques idées dans lesquelles j'ai:

  1. a fait l'hypothèse que httpsGetIntent () renvoie un Promsie qui fournit resultData .
  2. a promis checkAuthenticationStatus () en écrivant l'adaptateur checkAuthenticationStatusAsync () .
  3. a consolidé les commandes .speak () dans les clauses finales .then () et .catch () .
  4. permettait de personnaliser des erreurs spécifiques en décorant avec une propriété .title , qui est utilisée dans le .catch () final en tant que cardTitle. Toute erreur non décorée sera par défaut "Désolé" (ou ce que vous voulez).
// in a suitable scope ...
function checkAuthenticationStatusAsync(handlerInput) {
    return new Promise((resolve, reject) {
        checkAuthenticationStatus(handlerInput, (json) => {
            if (json.error || !json.noerror || json.noerror.okay !== 'true') {
                let err = new Error(messages.NO_ACCESS); // or maybe a separate error message per error case?
                err.title = 'Unauthorized Request';
                reject(err);
            } else {
                resolve(json);
            }
        });
    });
}

// ... and ...
const IntentRequest = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'IntentRequest';
    },
    handle(handlerInput) {
        return checkAuthenticationStatusAsync(handlerInput)
        .then((json) => httpsGetIntent(handlerInput, new URL(json.noerror.okay.path)))
        .then((resultData) => {
            if (resultData) {
                // success path ends here
                return handlerInput.responseBuilder.speak(resultData.response.outputSpeech.text).getResponse();
            } else {
                throw new Error('No result data returned'); // throws to the .catch() below
            }
        })
        .catch(err => {
            // all errors end up here.
            return handlerInput.responseBuilder.speak(err.message).withSimpleCard(err.title || 'Sorry', err.message).getResponse();
            throw err; // to keep handle's caller informed
        });
    },
};

Notez que c'est une façon, pas nécessairement la façon, d'écrire le code. N'hésitez pas à chercher des idées.


0 commentaires

0
votes

Votre meilleur ami est async / wait. Veuillez utiliser quelque chose comme ceci ou comme this pour accéder aux API.


1 commentaires

Merci pour ces exemples! Je vais essayer de les mettre en œuvre