Verwendung von async/await in der WeChat-Entwicklung

hzc
Freigeben: 2020-06-06 17:36:37
nach vorne
2712 Leute haben es durchsucht

Es gibt eine große Anzahl von Schnittstellen in WeChat-Miniprogrammen, die asynchron aufgerufen werden, wie z. B. wx.login(), wx.request(), wx.getUserInfo() usw., die alle ein Objekt als Parameter verwenden und definieren Success(), Fail() und Complete(), die in verschiedenen Situationen asynchroner Aufrufe als Rückrufe dienen.

Ein Programm in Form von Rückrufen zu schreiben ist jedoch wirklich ärgerlich. Wenn es einen Prozess gibt, der diese Dinge nacheinander ausführen muss:

  • wx.getStorage(. ), um die Cache-Daten zu erhalten, überprüfen Sie den Anmeldestatus

  • wx.getSetting(), um Konfigurationsinformationen zu erhalten,

  • wx.login() zu Melden Sie sich mit Konfigurationsinformationen an

  • wx.getUserInfo() ruft Benutzerinformationen nach der Anmeldung ab

  • wx.request() initiiert eine Datenanforderung an der Business-Server

Dann wird der Code wahrscheinlich so aussehen

wx.getStorage({
    fail: () => {
        wx.getSetting({
            success: settings => {
                wx.login({
                    success: ({ code }) => {
                        wx.getUesrInfo({
                            code,
                            success: (userInfo) => {
                                wx.request({
                                    success: () => {
                                        // do something
                                    }
                                });
                            }
                        });
                    }
                });
            }
        });
    }
});
Nach dem Login kopieren

Async/await kann natürlich dafür sorgen, dass der Code mit der gleichen Logik viel komfortabler aussieht. Allerdings unterstützen „WeChat Developer Tools“ standardmäßig kein Async/Await. Wie aktiviere ich?

1. Verwenden Sie async/await


Wenn Sie interessiert sind, suchen Sie in der offiziellen WeChat-Applet-Dokumentation nach „Tools ⇒ Entwicklungshilfe“. ⇒ Codekompilierung „Die Unterstützung für async/await wird auf der Seite erwähnt. Sie befindet sich in einer Tabelle im Abschnitt „Kompilierung hinzufügen“. Es gibt einen Auszug:

Entwicklungstools in 1.02 .1904282 und spätere Versionen wurde eine erweiterte Kompilierungsoption hinzugefügt, um die Fähigkeit zur Konvertierung von ES6 in ES5 zu verbessern. Wenn diese Option aktiviert ist, wird eine neue Kompilierungslogik verwendet und Entwicklern werden zusätzliche Optionen zur Verfügung gestellt.

  • Unterstützt die Async/Warten-Syntax, injiziert regeneratorRuntime bei Bedarf, der Verzeichnisspeicherort stimmt mit der Hilfsfunktion überein

Kurz gesagt: Solange die „WeChat Developer Tools“ auf Version 1.02.1904282 oder höher aktualisiert sind, ist es nicht erforderlich, Dinge wie den NPM-Installationsregenerator durchzuführen. Sie müssen lediglich ein Konfigurationselement ändern, um Async/Await zu verwenden Besonderheit. Diese Konfiguration finden Sie auf der Seite „Symbolleiste⇒Details⇒Lokale Einstellungen“.

Verwendung von async/await in der WeChat-Entwicklung

Um schnell zu überprüfen, ob async/await verfügbar ist, fügen Sie einen Code in die onLaunch()-Ereignisfunktion von app.js ein:

(async () => {    const p = await new Promise(resolve => {
        setTimeout(() => resolve("hello async/await"), 1000);
    });    console.log(p);
})();
Nach dem Login kopieren

Nach einer kurzen automatischen Kompilierung Nach dem Ausführen können Sie die Ausgabe auf der Registerkarte „Konsole“ der Debugger-Schnittstelle sehen:

hello async/await
Nach dem Login kopieren

Wenn nicht, überprüfen Sie bitte zuerst die Version der „WeChat Developer Tools“ – laden Sie zumindest die herunter Die neueste Version funktioniert nicht. Es liegt ein Problem vor.

2. Transformieren Sie die asynchrone Methode wx.abcd


Obwohl async/await unterstützt wird, muss wx.abcd geändert werden () muss nur im Promise-Stil gekapselt werden.

Node.js stellt im util-Modul promisify bereit, um Rückrufe im Node.js-Stil in den Promise-Stil zu konvertieren, aber offensichtlich funktioniert es nicht mit dem WX-Stil. Machen Sie es einfach selbst, und Sie müssen nicht zu viel nachdenken. Asynchrone Aufrufe im WX-Stil sind beispielsweise alle in ihrer Form konsistent:

  • Verwenden Sie an Objekt zum Übergeben aller Parameter, einschließlich drei Hauptrückrufe

  • success: (res) => jeder Rückruf, wenn die asynchrone Methode erfolgreich ist

  • fail : (err) = > beliebiger Rückruf, wenn die asynchrone Methode fehlschlägt

  • complete: () => beliebiger Rückruf, wenn die asynchrone Methode abgeschlossen wird (unabhängig von Erfolg oder Misserfolg)

Wenn also wx.abcd() in den Promise-Stil geändert und über async/await geschrieben wird, sollte es wahrscheinlich so aussehen

try {
    const res = wx.abcd();
    // do anything in success callback
} catch (err) {
    // do anything in fail callback
} finally {
    // do anything in complete callback
}
Nach dem Login kopieren

Natürlich der Haken Und schließlich müssen Teile nicht unbedingt einen Try-Block verwenden, d. h. sie müssen nicht unbedingt verwendet werden. Wenn der Fang jedoch nicht verwendet wird, gibt es eine Gefahr, die später besprochen wird. Das erste, was jetzt zu tun ist, ist die Transformation.

2.1. Definition promisify()

promisify() 就是一个封装函数,传入原来的 wx.abcd 作为参加,返回一个 Promise 风格的新函数。代码和解释如下:

function promisify(fn) {
    // promisify() 返回的是一个函数,
    // 这个函数跟传入的 fn(即 wx.abcd) 签名相同(或兼容)
    return async function(args) {
    //                    ^^^^ 接受一个单一参数对象
        return new Promise((resolve, reject) => {
    //             ^^^^^^^^^^^ 返回一个 Promise 对象
            fn({
    //      ^^ ^ 调用原函数并使用改造过的新的参数对象
                ...(args || {}),
    //          ^^^^^^^^        这个新参数对象得有原本传入的参数,
    //                      ^^  当然得兼容没有传入参数的情况
                success: res => resolve(res),
    //          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^  注入 success 回调,resovle 它
                fail: err => reject(err)
    //          ^^^^^^^^^^^^^^^^^^^^^^^^ 注入 fail 回调,reject 它
            });
        });
    };
}
Nach dem Login kopieren

举例使用它:

const asyncLogin = promisify(wx.login);  // 注意别写成 wx.login(),为什么,我不说
try {
    const res = asyncLogin();
    const code = res.code;
    // do something with code
} catch (err) {
    // login error
} finally {
    // promisify 里没有专门注入 complete 回调,
    // 因为 complete 的内容可以写在这里
}
Nach dem Login kopieren

2.2. 定义 wx.async()

不过老实说,把要用的异步方法通过 promisify 一个个处理,写起来还是挺烦的,不如写个工具函数把要用的方法一次性转换出来。不过一查,wx 下定义了不知道多少异步方法,还是退而求其次,用到啥转啥,不过可以批量转,转出来的结果还是封装在一个对象中。整个过程就是迭代处理,最后把每个处理结果聚焦在一起:

function toAsync(names) {    // 这里 names 期望是一个数组
    return (names || [])
        .map(name => (
            {
                name,
                member: wx[name]
            }
        ))
        .filter(t => typeof t.member === "function")
        .reduce((r, t) => {
            r[t.name] = promisify(wx[t.name]);
            return r;
        }, {});
}
Nach dem Login kopieren

这个 toAsync 的用法大致是这样的

const awx = toAsync(["login", "request"]);
await awx.login();
await awx.request({...});
Nach dem Login kopieren

有些人可能更习惯单个参数传入的方式,像这样

const awx = toAsync("login", "request");
Nach dem Login kopieren

那么在 toAsync 的定义中,参数改为 ...names 就好,即

function toAsync(...names) { ... }
Nach dem Login kopieren

还没完,因为我不想在每一个 JS 文件中去 import { toAsync } from ...。所以把它在 App.onLaunch() 中把它注入到 wx 对象中去,就像这样

App({
    onLaunch: function() {
        // ...
        wx.async = toAsync;
        // ...
    }
});
Nach dem Login kopieren

3. await 带来的神坑

工具准备好了,代码也大刀阔斧地进行了改造,看起来舒服多了,一运行却报错!为什么???

先来看一段原来的代码,是这样的

wx.getStorage({
    key: "blabla",
    success: res => {
        // do with res
    }
});
Nach dem Login kopieren

改造之后是这样

const res = await awx.getStorage({ key: "blabla" });  // <== runtime error
// do with res
Nach dem Login kopieren

awx.getStorage 抛了个异常,原因是叫 "blabal" 的这个数据不存在。

为什么原来没有错,现在却报错?

因为原来没有定义 fail 回调,所以错误被忽略了。但是 promisify() 把 fail 回调封装成了 reject(),所以 awx.getStorage() 返回的 Promise 对象上,需要通过 catch() 来处理。我们没有直接使用 Promise 对象,而是用的 await 语法,所以 reject() 会以抛出异常的形式体现出来。

用人话说,代码得这样改:

try {
    const res = await awx.getStorage({ key: "blabla" });  // <== runtime error
    // do with res
} catch (err) {
    // 我知道有错,就是当它不存在!
}
Nach dem Login kopieren

伤心了不是?如果没有伤心,你想想,每一个调用都要用 try ... catch ... 代码块,还能不伤心吗?

3.1. 忽略不需要处理的错误

处理错误真的是个好习惯,但真的不是所有错误情况都需要处理。其实要忽略错误也很简单,直接在每个 Promise 形式的异步调后面加句话就行,比如

const res = await awx
    .getStorage({ key: "blabla" })
    .catch(() => {});
//  ^^^^^^^^^^^^^^^^ 捕捉错误,但什么也不干
Nach dem Login kopieren

稍微解释一下,在这里 awx.getStorage() 返回一个 Promise 对象,对该对象调用 .catch() 会封装 reject 的情况,同时它会返回一个新的 Promise 对象,这个对象才是 await 等待的 Promise。

不过感觉 .catch(() => {}) 写起来怪怪的,那就封装成一个方法吧,这得改 Promise 类的原形

Promise.prototype.ignoreError = function() {
    return this.catch(() => { });
};
Nach dem Login kopieren

这段代码放在定义 toAsync() 之前就好。

用起来也像那么回事

const res = await awx
    .getStorage({ key: "blabla" })
    .ignoreError();
Nach dem Login kopieren

对于单个 await 异步调用,如果不想写 try ... catch ... 块,还可以自己定义一个 ifError(fn) 来处理错误的情况。但是如果需要批量处理错误,还是 try ... catch ... 用起顺手:

4. 回到开始

try {
    const storeValue = await awx.getStorage({});
    const settings = await awx.getSetting();
    const { code } = await awx.login();
    const userInfo = await awx.getUserInfo({ code });
} catch (err) {
    // 处理错误吧
}
Nach dem Login kopieren

看,不需要对每个异步调用定义 fail 回调,一个 try ... catch ... 处理所有可能产生的错误,这可不也是 async/await 的优势!

推荐教程: 《微信小程序

Das obige ist der detaillierte Inhalt vonVerwendung von async/await in der WeChat-Entwicklung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:segmentfault.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage