Maison  >  Article  >  Applet WeChat  >  Améliorer l'encapsulation asynchrone : gérer les appels asynchrones avec des valeurs de retour - Border City Inn

Améliorer l'encapsulation asynchrone : gérer les appels asynchrones avec des valeurs de retour - Border City Inn

hzc
hzcavant
2020-06-23 10:07:232934parcourir
Les derniers articles sont liés au développement de mini-programmes WeChat, alors quelqu'un a demandé : "Je ne comprends pas les mini-programmes, pouvez-vous écrire autre chose ?".

En fait, vous n'avez pas besoin de prêter trop d'attention au « petit programme », car le « petit programme » n'est qu'un scénario de développement dans l'article. Les problèmes que nous résolvons réellement ne se rencontrent pas uniquement dans les petits programmes. , et les moyens pour résoudre le problème sont complètement Cela n'a rien à voir avec des mini programmes !

1. Problème

laisse un problème dans l'appel asynchrone du proxy encapsulant l'applet WeChat :

est comme wx.request() Comment faire encapsuler cette situation où il y a une valeur de retour ?

Si vous devez annuler la demande pendant le processus de demande, la valeur de retour de wx.request() sera utilisée :

const requestTask = wx.request(...);
if (...) {
    // 因为某些原因需要取消这次请求
    requestTask.abort();
}

Le awx.request() encapsulé renverra un objet Promise, suivi de wx.request() La valeur de retour d'origine n'a rien à voir avec cela. Si vous souhaitez pouvoir annuler la demande, vous devez faire ressortir la valeur de retour originale de wx.request(). Que devez-vous faire ?

function wxPromisify(fn) {
    return async function (args) {
        return new Promise((resolve, reject) => {
            const originalResult = fn({
//          ^^^^^^^^^^^^^^^^^^^^^^^
//          怎么把 originalResult 带出去?
                ...(args || {}),
                success: res => resolve(res),
                fail: err => reject(err)
            });
        });
    };
}

2. Alternatives

Ce n'est pas trop compliqué, voici plusieurs options :

  1. Renvoyer un objet ou un tableau, utilisé après déconstruction . Par exemple, return { promise, originalResult} ou [promise, originalResult];
  2. fait ressortir la valeur de retour via un paramètre "conteneur", tel que awx.request(params, outBox = {}), et attribue une valeur à outBox lors du traitement : outBox.originalResult ;
  3. JS est un type dynamique et peut directement modifier l'objet Promise et lui ajouter des attributs : promise.originalResult = ....

Du point de vue de l'utilisateur, la plupart du temps, la valeur de retour d'origine n'est pas nécessaire pour le moment, nous voulons absolument await awx.request() au lieu de déconstruire d'abord, puis await (ou ), la première méthode n’est donc pas facultative. then()

La deuxième méthode est réalisable et peut être utilisée directement lorsque la valeur de retour d'origine n'est pas nécessaire. Mais lorsque vous avez besoin de la valeur de retour d'origine, c'est un peu gênant. Vous devez d'abord générer un objet conteneur et le transmettre.

La troisième méthode devrait être la plus « se sentir libre » à utiliser. Dans tous les cas, la valeur d'origine est mise en évidence avec l'objet Promise, utilisez-le ou non, n'hésitez pas à l'utiliser !

Implémentons maintenant la troisième méthode, la transformation

 : wxPromisify()

Tentative échouée

C'était très simple au début, avant. être directement

, mais maintenant il devrait suffire d'ajouter une variable temporaire : return new Promise()

function wxPromisify(fn) {
    return async function (args) {
        const promise = new Promise((resolve, reject) => {
//      ^^^^^^^^^^^^^^^^
            promise.originalResult = fn({
//          ^^^^^^^^^^^^^^^^^^^^^^^^^
                ...(args || {}),
                success: res => resolve(res),
                fail: err => reject(err)
            });
        });
        
        return promise;
//      ^^^^^^^^^^^^^^^
    };
}
et d'obtenir ensuite une erreur :

TypeError: Cannot set property 'originalResult' of undefined
Cette erreur est facile à comprendre et facile à corriger.. . mais c'est effectivement très facile de s'engager !

À l'origine, on pensait que

était une variable locale accessible directement, il n'y avait donc aucun problème à l'utiliser dans sa sous-portée. Mais on ignore ici que cette sous-portée est dans le constructeur. Faisons une analyse grossière : promise

nécessite une fonction (supposée être appelée new Promise()) comme paramètre, mais quel est le timing d'exécution de cette factory ? Notez qu'après que factory a généré une instance Promise, nous n'appelons jamais activement aucune méthode de cette instance, nous pouvons donc conclure que new Promise() est exécuté pendant le processus de construction. En d'autres termes, l'instance Promise n'a pas encore été générée pour le moment, et factory fait référence à promise. undefined

4. Tentative réussie

Maintenant que nous connaissons le problème, poursuivons l'analyse.

appelle

dans le processus de construction de l'instance Promise, et factory exécute directement factory dans le corps de la fonction, et vous pouvez obtenir la valeur de retour de fn immédiatement, donc cette instance Promise construction Une fois terminé, vous pouvez obtenir la valeur de retour originale. fn

Modifions maintenant le code :

function wxPromisify(fn) {
    return async function (args) {
        let originalResult;
//      ^^^^^^^^^^^^^^^^^^^
        const promise = new Promise((resolve, reject) => {
            originalResult = fn({
//          ^^^^^^^^^^^^^^
                ...(args || {}),
                success: res => resolve(res),
                fail: err => reject(err)
            });
        });

        promise.originalResult = originalResult;
//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        return promise;
    };
}
Nous devons attribuer une valeur à

après new Promise(), et cette "valeur" est générée dans le processus de promise.originalResult, puis ajoutez une autre variable locale new Promise() Faites-la simplement ressortir. originalResult

C'est fait !

5. Des choses qui sont drôles mais qui doivent être prises au sérieux

Cela aurait dû se terminer, mais je suppose que quelqu'un le fera (car je l'ai vu dans d'autres scènes ) :

Remarque : ce qui suit est un exemple d'erreur !
function wxPromisify(fn) {
    return async function (args) {
        let promise = new Promise();
//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        promise = new Promise((resolve, reject) => {
//      ^^^^^^^^^^
            promise.originalResult = fn({ ... });
//          ^^^^^^^^^^^^^^^^^^^^^^
        });

        return promise;
    };
}
Faire cela ne produira pas le

susmentionné, mais l'objet Promise obtenu de l'extérieur ne porte pas TypeError. La raison spécifique est la même que celle de la tentative échouée ci-dessus, je n'entrerai donc pas dans les détails. Juste un rappel : originalResultDeux objets Promise sont générés ici.

6. Parlons-en encore

Cette fois, la valeur de retour d'origine est ressortie en utilisant wx.request() comme exemple. Le but principal de sa valeur de retour est de fournir le. .abort() méthode de demande d'annulation. Ce scénario d'application est en fait similaire à la façon dont Axios gère « Annulation », vous pouvez donc aussi bien vous référer à la méthode implémentée par Axios via cancelToken. L'essence de cancelToken est la deuxième méthode mentionnée ci-dessus : passer l'objet "conteneur" pour faire ressortir les éléments nécessaires. Le faire ressortir via un objet Promise revient essentiellement à le faire ressortir via un objet "conteneur" spécial, donc je n'en dirai pas plus.

Tutoriel recommandé : "Programme WeChat Mini"

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer