Jede Anwendung, die in JavaScript geschrieben werden kann, wird irgendwann auch in JavaScript geschrieben. Ebenso wird jedes Produkt, das mithilfe von Miniprogrammen implementiert werden kann, irgendwann auch mithilfe von Miniprogrammen implementiert. Wie entwickelt man also ein kleines Programm? Der folgende Artikel fasst fünf Jahre Erfahrung in der Entwicklung kleiner Programme für E-Commerce-Frontend-Teams zusammen (10.000-Wörter-Prinzip + Optimierungstipps) und ist für alle hilfreich!
Fragen zum zugrunde liegenden Design von WeChat-Miniprogrammen
- Was genau ist das Dual-Threaded-Modell?
- Wie trennt man Ansicht und Logik?
- Warum seltsame Syntax wie WXML und WXSS verwenden?
- Wie blockiert man die API für gefährliche Vorgänge?
- Wie kommuniziert man und wie implementiert man datengesteuerte Ansichtsaktualisierungen?
- Was sind die Nachteile des Dual-Threaded-Modells?
Leistungsprobleme
Der Rendering-Thread und der JS-Engine-Thread schließen sich gegenseitig aus Blockierungsprobleme wirken sich direkt auf die Darstellung von UI-Ansichten aus und verursachen Sicherheitsprobleme. Gefährliche HTML-Tags (a, script) und JS-APIs (Function, eval, DOM API). Für Angreifer ist es leicht, Seiteninhalte zu manipulieren, illegal an Benutzerinformationen zu gelangen usw.
Lösung
Das Applet verwendet ein Dual-Thread-Modell, das die Ansichtsanzeige und die Logikverarbeitung in zwei Threads trennt.
Im Modell-HTML Tags sind gekapselt, sodass Entwickler die ursprünglichen gefährlichen Logikoperations-API-Funktionen in JS ebenfalls blockieren können. Die beteiligten Kommunikationsaktionen können nur virtuelle DOM-Aktualisierungen (datengesteuerte Ansichten) über die von der mittleren Schicht bereitgestellte API auslösen. )
2), Miniprogramm-Dual-Thread-ModellWAWebview.js Bietet grundlegende API-Funktionen für die Ansichtsschicht, einschließlich eines vollständigen Satzes von Komponentensystemen und zugehörigen Implementierungen von Virtual Dom
WAService.jsBietet grundlegende API-Funktionen für die Logikschicht und stellt Entwicklern APIs für verschiedene Vorgänge zur Verfügung
3) Die zugrunde liegende Implementierung der Client-EngineUnter verschiedenen Betriebsumgebungen sind die Skriptausführungsumgebung und die Umgebung für das Komponenten-Rendering unterschiedlich, und auch die Leistungsleistung ist unterschiedlich:
ausgeführt und die Ansichtsebene wird von WKWebView gerendert. Die Umgebung umfasst iOS 14, iPad OS 14, Mac OS 11.4 usw.
Auf Android ist der JavaScript-Code des Applet-Logikschicht: Beim Ausführen in V8 wird die Ansichtsebene von der selbst entwickelten XWeb-Engine von WeChat basierend auf dem Mobile Chromium-Kern gerendert (vom früheren X5 bis zur selbst entwickelten Kern und Offiziellen Angaben zufolge wird die Logikschicht in Zukunft auch von V8 getrennt, indem benutzerdefinierte XWeb-Worker-Threads verwendet werden, d
Auf dem Entwicklungstool läuft der JavaScript-Code der Applet-Logikschicht in NW.js und der Ansichtsschicht wird von Chromium WebView gerendert
2. Ansichtsebene
Webkomponente ist die Möglichkeit, gekapselte Funktionen und benutzerdefinierte Elemente im Browser zu erstellen und besteht aus drei Haupttechnologien
Benutzerdefinierte Elemente (benutzerdefinierte Elemente) Eine Reihe von JavaScript-APIs, die es ermöglichen, benutzerdefinierte Elemente und deren Verhalten zu definieren und sie dann nach Bedarf in der Benutzeroberfläche zu verwenden.
Shadow DOM (Shadow DOM) Eine Reihe von JavaScript-API zum Anhängen eines gekapselten „Schatten“-DOM-Baums an ein Element (getrennt vom Hauptdokument-DOM gerendert) und zum Steuern der zugehörigen Funktionalität. Dadurch, dass die Funktionalität der Elemente auf diese Weise privat gehalten wird, können sie mit Skripten und Stilen versehen werden, ohne Konflikte mit anderen Teilen des Dokuments befürchten zu müssen die gerenderte Seite. Sie können dann mehrfach als Grundlage für benutzerdefinierte Elementstrukturen wiederverwendet werden
Exparser verwaltet Informationen zum Knotenbaum der gesamten Seite, einschließlich Knotenattributen, Ereignisbindungen usw., was einer vereinfachten Version der Shadow DOM-Implementierung entspricht
registerElement
Registrieren Sie die Komponente und interagieren Sie mit uns. Hauptsächlich Eigenschaften und EreignisseErstellung von Komponenten
Erweitern Sie die Möglichkeiten des Webs. Beispielsweise verfügen Eingabefeldkomponenten (Eingabe, Textbereich) über die Möglichkeit, die Tastatur besser zu steuern.
Bessere Erfahrung
und gleichzeitig die Renderarbeit von WebView reduzieren. Beispielsweise belegt die Rendering-Arbeit komplexerer Komponenten wie Kartenkomponenten nicht den WebView-Thread, sondern wird zur nativen Verarbeitung an den effizienteren Client übergeben.
Bessere Rendering-Leistung
unter Umgehung des SetData-, Datenkommunikations- und Re-Rendering-Prozesses. Beispielsweise können Canvas-Komponenten (Canvas) direkt mit einem umfangreichen Satz an Zeichenschnittstellen gezeichnet werden.2. Prozess der nativen Komponentenerstellung
Die Komponente benachrichtigt den Client, und der Client fügt basierend auf Breite und Höhe einen nativen Bereich an derselben Position ein, und dann rendert der Client die Schnittstelle in diesem Bereich
Wenn sich die Position oder Breite und Höhe ändern, Die Komponente wird benachrichtigt. Der Client nimmt entsprechende Anpassungen vor die WebView-Ebene)
4), natives Komponenten-Rendering auf gleicher Ebene
1. iOS-Systemimplementierungsprinzip
Erstellungsprozess
Erstellen Sie einen DOM-Knoten und setzen Sie seine CSS-Eigenschaften auf overflow: scroll und -webkit-overflow-scrolling: touch
Benachrichtigen Sie den Client, um den nativen Knoten zu finden, der dem DOM entspricht Knoten Die WKChildScrollView-Komponente
mountet die native Komponente als untergeordnete Ansicht in den WKChildScrollView-Knoten
Durch den obigen Prozess wird die native Komponente des Applets in die WKChildScrollView eingefügt
2. Android-Systemimplementierungsprinzip
Erstellen Sie einen eingebetteten DOM-Knoten auf der WebView-Seite und geben Sie den Komponententyp an.
Der Chromium-Kernel erstellt eine WebPlugin-Instanz und generiert einen RenderLayer
Der Android-Client initialisiert eine entsprechende native Komponente.
Der Android-Client zeichnet das Bild der nativen Komponente in die SurfaceTexture, die an den in Schritt 2 erstellten RenderLayer gebunden ist.
1 Eine Konvertierungsmethode zum Hinzufügen der Größeneinheit rpx, die entsprechend der Bildschirmbreite des Geräts adaptiv in px-Einheiten berechnet werden kann.
Stellen Sie die setCssToHead-Methode bereit, um den konvertierten CSS-Inhalt zum Kopf der HTML-Vorlage hinzuzufügen um diese JS-Dateizeichenfolge auszuführen, um die Stilinjektion abzuschließen
?? Dateipfad nach der Ausführung. Generieren Sie die Methode „generateFunc“ und lösen Sie das Ereignis „generateFuncReady“ aus. Die Methode „generateFunc“ akzeptiert dynamische Datendaten, ähnlich einer Renderfunktion, die zum Generieren eines virtuellen Doms verwendet wirdFügt eine Modulschnittstelle hinzu, für die eine Definition für das Fensterobjekt erforderlich ist
Stellt Seiten-, App-, getApp- und andere Schnittstellen bereit
Stellt API-Methoden bereit unter wx globales Objekt, Netzwerk, Medien, Dateien, Datencache, Standort, Gerät, Schnittstelle, Schnittstellenknoteninformationen und einige spezielle offene Schnittstellen
2), JS-Code-Ausführungsumgebung
iOS,
Android3, JSValue
Verwenden Sie „require“, um ein Modul anzuwenden Bei Verwendung eines Moduls werden nur „require“, „module“ und „exports“ übergeben. Andere im Code gelesene Variablen sind auch der Grund, warum einige Browserumgebungsobjekte im Miniprogramm nicht abgerufen werden können
Dies ist eigentlich eine typische Idee zum Laden von Modulen, die der Art und Weise, wie Webpack Module paketiert, sehr ähnlich istDie verschiedenen Implementierungen mehrerer Enden werden schließlich in einer Kompatibilitätsschicht wie WeiXinJSBridge gekapselt, damit Entwickler sie aufrufen können1 Die iOS-Seite
Ansichtsschicht ist durch window.webkit.messageHandlers.NAME von WKWebView .postMessage und Eval-Implementierung. Die Logikschicht fügt eine globale native Methode in das JavaScriptCore-Framework ein2 Die Implementierungsprinzipien der Ansichtsschicht und der Logikschicht sind die gleichen. Sie werden durch Einfügen einer nativen Methode WeixinJSCore in das Fenster implementiert Objekt von WebView. Dieses WeixinJSCore ist eine WeChat-Schnittstelle (native Implementierung), die für JS-Aufrufe bereitgestellt wird. Ansichtsschicht und Logikschicht Der Nachrichtenkommunikationsmechanismus zwischen ihnen bietet die folgenden Methoden:
invoke: JS ruft die native API auf
on: JS hört auf native Nachrichten
publish: View-Layer veröffentlicht Nachrichten
subscribe: Abonniert Logik-Layer-Nachrichten
kann DOM nicht flexibel bedienen und kann keine komplexeren Effekte erzielen
Einige Ansichten im Zusammenhang mit nativen Komponenten unterliegen Nutzungsbeschränkungen, wie z. B. WeChats scrollView kann keinen Textbereich haben
Die Seitengröße und die Anzahl der geöffneten Seiten sind begrenzt
Erfordert separate Entwicklung und Anpassung, kann vorhandene Coderessourcen nicht wiederverwenden
Wenn das JS-Volumen in JSCore relativ groß ist, wird die Initialisierungszeit beeinträchtigt
Bei der Datenübertragung muss der Zeitaufwand für Serialisierung und Deserialisierung berücksichtigt werden
Der durch Dual-Threads verursachte Leistungsengpass ist auch ein zentrales Problem von WeChat selbst hat sich der Lösung verschrieben. Wie bereits erwähnt, ersetzt das Applet die Implementierung der Logikschicht durch einen benutzerdefinierten XWeb-Worker-Thread, indem es den Chromium-Kernel im neuen XWeb-Kernel ändert. Dadurch wird die Notwendigkeit zusätzlicher V8 beseitigt und die Speichernutzung erheblich reduziert. Da es außerdem in Bezug auf die Datenkommunikation auf dem Worker-Thread des Chromium-Kernels basiert, ist es selbstverständlich, dass PostMessage die ursprüngliche zugrunde liegende Kommunikationsmethode setData ersetzen kann, um leistungsfähigere Kommunikationsfunktionen zu erhalten
Darüber hinaus habe ich auch die zugrunde liegende Implementierung des Alipay-Applets kennengelernt und studiert. Das Alipay-Applet verwendet ebenfalls ein ähnliches Dual-Thread-Architekturmodell. Durch die Verwendung des von UC bereitgestellten Browserkernels wird die Rendering-Schicht im Webview-Thread ausgeführt und die Logikschicht startet einen separaten Thread, um den Service Worker auszuführen. Allerdings muss der Service Worker über die MessageChannel-API mit dem Rendering-Thread kommunizieren. Wenn die Datenmenge groß und die Objekte komplex sind, kommt es auch zu Leistungsengpässen.
Daher hat das Alipay-Applet die vorhandene virtuelle JS-Maschine V8 neu gestaltet und ein optimiertes Isolationsmodell (Optimized Isolation Model, OIM) vorgeschlagen. Die Hauptidee von OIM besteht darin, Daten und Infrastruktur in Instanzen virtueller JS-Maschinen zu teilen, die nichts mit der Thread-Ausführungsumgebung zu tun haben, sowie unveränderliche oder unveränderliche JS-Objekte, sodass unter Beibehaltung der logischen Isolation der JS-Schicht Speicher kann in Multi-Instanz-Szenarien und Stromverbrauch eingespart werden. Obwohl einige zwischen Instanzen gemeinsam genutzte Daten einen Synchronisierungsaufwand mit sich bringen, sind die von dieser Lösung gemeinsam genutzten Daten, Objekte, Codes und virtuellen Maschineninfrastrukturen im Rahmen des Isolationsmodells unveränderlich oder nichtflüchtig, sodass es selten zu Wettbewerb kommt.
Unter dem neuen Isolationsmodell ist die V8-Instanz in Webview eine lokale Laufzeit, und die V8-Instanz im Worker-Thread ist auch eine lokale Laufzeit. Wenn die Logikebene und die Rendering-Ebene interagieren, wird das setData-Objekt direkt in erstellt Gemeinsamer Heap. Daher kann die lokale Laufzeit der Rendering-Ebene das Objekt direkt lesen und zum Rendern der Rendering-Ebene verwenden, was die Serialisierung und Netzwerkübertragung des Objekts reduziert und die Startleistung und Rendering-Leistung erheblich verbessert.
Darüber hinaus implementiert das Alipay-Applet die Homepage-Offline-Caching-Optimierung. Es rendert zunächst die zuletzt gespeicherte Homepage-UI-Seite, zeigt dem Benutzer die Homepage an und lädt anschließend das Front-End-Framework und den Geschäftscode weiter Wenn der Ladevorgang abgeschlossen ist, wird er mit der offline zwischengespeicherten Homepage-Benutzeroberfläche zusammengeführt, um den Benutzern eine dynamische Homepage anzuzeigen. Dies ist der anfänglichen Rendering-Caching-Lösung des WeChat-Applets sehr ähnlich und radikaler. Die WebAssembly-Technologie wurde auch verwendet, um den Kerncode des virtuellen DOM neu zu implementieren und die Seitendarstellung des Miniprogramms zu verbessern. [Empfohlene verwandte Video-Tutorials: Web-Frontend]
Eine gute technische Lösung erfordert nicht nur, dass Designer die Entwicklungseffizienz verbessern technische Kosten, Leistungserfahrung und Systemsicherheit, es muss auch eng mit Geschäftstrends, Produktformen und Benutzeranforderungen integriert werden
Wenn das Miniprogramm startet (Kaltstart), zeigt WeChat eine feste Startoberfläche für das Miniprogramm an, die das Symbol, den Namen und das Ladeaufforderungssymbol des Miniprogramms enthält
Zu diesem Zeitpunkt führt WeChat mehrere aus Dinge hinter den Kulissen Arbeit: Laden Sie das Mini-Programmcode-Paket herunter, laden Sie das Mini-Programm-Codepaket und initialisieren Sie die Mini-Programm-Homepage
Aus Entwicklersicht trägt die Kontrolle der Größe des Codepakets dazu bei, die Startzeit des Miniprogramms zu verkürzen. Für Codepakete unter 1 MB kann die Downloadzeit innerhalb von 929 ms (iOS) bzw. 1500 ms (Android) im Rahmen des
Optimierungsplans
gesteuert werden. Reduzieren Sie die Größe des Hauptpakets und der Unterpakete. Paket
Rationale Zuweisung, Unterauftragsvergabe und Vorladeregeln
Feine Aufteilung, asynchrone Unterauftragsvergabe
Bevor das Miniprogramm gestartet wird, bereitet WeChat im Voraus eine Seitenebene vor die Homepage des Miniprogramms. Immer wenn eine Seitenebene zum Rendern einer Seite verwendet wird, beginnt WeChat im Voraus mit der Vorbereitung einer neuen Seitenebene, sodass bei jedem Aufruf von wx.navigateTo so schnell wie möglich eine neue Seite angezeigt werden kann. Der Inhalt der Ansichtsebenenseite wird über die Vorlage pageframe.html generiert
Vorbereitungsschritte für die Seitenebene
Der erste Schritt besteht darin, eine WebView zu starten. Auf iOS- und Android-Systemen. Das Starten von WebView durch das Betriebssystem dauert nur kurze Zeit. Der zweite Schritt besteht darin, die Basisbibliothek in WebView zu initialisieren. Zu diesem Zeitpunkt werden auch einige interne Optimierungen der Basisbibliothek durchgeführt, um die Leistung beim Rendern von Seiten zu verbessern
Der dritte Schritt besteht darin, die WXML-Struktur des Applets und den WXSS-Stil einzufügen, sodass das Miniprogramm sofort nach Erhalt der Anfangsdaten der Seite mit dem Rendern der Seite beginnen kann (dieser Schritt kann nicht ausgeführt werden, bevor das Miniprogramm gestartet wird)__wxAppCode__: Nicht-JS-Entwicklercode JSON: Inhalt der JSON-Konfigurationsdatei
__wxAppCode__: Ähnlich wie die Ansichtsebene, enthält keine Daten vom Typ WXSS__wxRoute: Wird verwendet, um auf den Pfad der Seite zu verweisen, die gerade geladen wird
Führen Sie $gwx (aktueller Seitenpfad) aus und geben Sie die entsprechende Methode zurück, um ein virtuelles DOM zu generieren und führen Sie die Datei wxml.js aus (definieren Sie die $gwx-Methode)
4, Datenkommunikation und Ansichtsrendering
im Miniprogramm Beim Starten oder Öffnen einer neuen Seite werden die Anfangsdaten (Daten) und der Pfad sowie andere zugehörige Informationen der Seite von der Logikebene an die Ansichtsebene gesendet, um die Ansichtsebene zunächst zu rendern.
Die native Ebene übergibt diese Daten direkt an die Ansichtsebene und präsentiert dem Benutzer eine neue Seitenebene. Die Ansichtsebene zeichnet die Schnittstelle auf dieser Seitenebene.
Nachdem die Ansichtsebene die relevanten Daten empfangen hat, wählt sie die entsprechende WXML-Struktur entsprechend dem Seitenpfad aus. Die WXML-Struktur wird mit den Anfangsdaten kombiniert, um das erste Rendering-Ergebnis der Seite zu erhalten Code-Injektion und -Erfassung der Ansichtsschicht Nach dem Empfang der von der Logikschicht gesendeten Anfangsdaten in Kombination mit den aus den Anfangsdaten und der Ansichtsschicht erhaltenen Seitenstruktur- und Stilinformationen rendert das Miniprogramm-Framework die Homepage des Miniprogramms und zeigt die an Öffnen Sie den ersten Bildschirm des Miniprogramms und lösen Sie das onReady-Ereignis auf der Startseite aus.
Wenn der Initial-Rendering-Cache
aktiviert ist, kann das erste Rendering direkt mit den zwischengespeicherten Daten der Rendering-Ebene abgeschlossen werden, ohne auf die Anfangsdaten der Logikebene angewiesen zu sein, wodurch die Startzeit verkürzt wird (das onReady-Ereignis wird in ausgeführt). Vorauszahlung).Die Seiteninitialisierungszeit besteht grob aus zwei Teilen: der anfänglichen Datenkommunikationszeit der Seite und der anfänglichen Renderzeit. Dabei bezieht sich die Datenkommunikationszeit auf die Zeit vom Beginn der Datenorganisation auf der Logikschicht bis zum Abschluss des vollständigen Empfangs durch die Ansichtsschicht. Wenn das Datenvolumen weniger als 64 KB beträgt, kann die Gesamtzeit innerhalb von 30 ms gesteuert werden.
Die Übertragungszeit korreliert im Allgemeinen positiv mit der Datenmenge. Die Übertragung übermäßig großer Datenmengen verlängert sich diesmal erheblich. Daher ist die Reduzierung der übertragenen Datenmenge eine wirksame Möglichkeit, die Datenübertragungszeit zu verkürzen.
Erstes Rendern
Das erste Rendern erfolgt, wenn die Seite gerade erstellt wird. Beim ersten Rendern werden die Anfangsdaten auf das entsprechende WXML-Fragment angewendet, um einen Knotenbaum zu generieren. Der Knotenbaum ist die Seitenbaumstruktur, die im WXML-Bereich der Entwicklertools angezeigt wird. Er enthält Informationen wie Namen, Attributwerte, Ereignisrückruffunktionen und andere Informationen aller Komponentenknoten auf der Seite. Schließlich wird jede Komponente auf der Schnittstelle basierend auf jedem im Knotenbaum enthaltenen Knoten nacheinander erstellt. Die beim ersten Rendering erhaltenen Daten und der aktuelle Knotenbaum werden für ein erneutes Rendering beibehalten.
In diesem gesamten Prozess ist der Zeitaufwand im Allgemeinen proportional zur Gesamtzahl der Knoten im Knotenbaum. Daher kann
Durch die Reduzierung der Anzahl der Knoten in WXMLder Zeitaufwand für das anfängliche Rendern und erneute Rendern effektiv reduziert und die Rendering-Leistung verbessert werden.
2) Datenrendering aktualisieren
Nach Abschluss des ersten Renderings kann die Ansichtsebene Schnittstellenaktualisierungen durchführen, nachdem der Entwickler setData aufgerufen hat.
{abc: 1} 中 abc 属性名 => [abc] {a.b.c: 1} 中 'a.b.c' 属性 => [a,b,c] {"array[0].text": 1} => [array, 0, text]2. Senden Sie Daten von der Logikschicht an die Ansichtsschicht (asynchroner Vorgang).
evaluateJavascript
: Die vom Benutzer übertragenen Daten müssen in eine Zeichenfolgenform konvertiert und an übergeben werden Gleichzeitig wird der konvertierte Dateninhalt in ein JS-Skript gespleißt und dann durch Ausführen des JS-Skripts an die unabhängigen Umgebungen auf beiden Seiten übergeben. Beim erneuten Rendern führt die Logikschicht die setData-Daten zu Daten zusammen Die Rendering-Ebene wendet die Daten und setData-Daten auf das WXML-Fragment an, um einen neuen Knotenbaum zu erhalten. Vergleichen Sie dann den neuen Knotenbaum mit dem aktuellen Knotenbaum, damit Sie feststellen können, welche Knoten aktualisiert und welche Knoten hinzugefügt oder entfernt werden müssen. Schließlich wird der alte Knotenbaum für das nächste erneute Rendern durch den neuen Knotenbaum ersetzt. Beim Vergleich des aktuellen Knotenbaums und des neuen Knotenbaums werden die von den setData-Daten betroffenen Knotenattribute verglichen. Daher trägt das Entfernen unnötiger Set-Daten und die Reduzierung der Datenmenge in setData auch dazu bei, die Leistung dieses Schritts zu verbessern.3), Benutzerereigniskommunikation
Die Ansichtsebene akzeptiert Benutzerereignisse wieKlickereignisse, Berührungsereignisse usw.
Die Kommunikation von Benutzerereignissen ist relativ einfach. Wenn ein Benutzerereignis ausgelöst wird und ein zugehöriger Ereignis-Listener ausgelöst werden muss, gibt die Ansichtsschicht die Informationen an die Logikschicht zurück.
Da dieser Kommunikationsprozess asynchron ist, kommt es zu einer gewissen Verzögerung. Die Verzögerungszeit hängt auch positiv von der übertragenen Datenmenge ab und liegt innerhalb von 30 ms.
Entfernen Sie unnötige Ereignisbindungen (Binden und Fangen in WXML), wodurch die Menge und Anzahl der Kommunikationsdaten reduziert wird currentTarget muss übertragen werden. Platzieren Sie daher keine zu großen Daten im Datenpräfixattribut des Knotens
主包内容
Tab页(系统要求)、业务必要页面(错误兜底页、登陆授权页等),其余文件都以业务模块或者页面的维度,拆分成各自的分包
分包预加载
据用户的实际使用场景,预测下一跳的页面,将可能性最高的场景设置为预加载分包(可以参照业务埋点数据),例如:进入电商首页后,需要对会场和商详页的分包进行预加载
实现思路
小程序不支持主包引用分包代码,只能在分包中引用主包代码,所以把公共使用的组件代码放在主包目录中,但这些公共组件未必在主包所属的页面中会被引用,可能只是在分包页面中被多次引用,这样使得主包中代码体积越来越大,用户首次加载速度变慢。
将主包页面不依赖的公共组件分别分发到依赖它们的分包目录中,虽然分包各自的体积会有所增大,但主包体积会有显著下降
实现原理
将所有需要分发的组件放置主包指定目录中,并添加配置文件,说明组建文件分发信息。在开发时用 gulp 任务监听单个文件变化、在构建时递归遍历所有组件,将其复制到配置文件中指定的子包路径目录中。
目标文件在复制之前,都先要将文件内的依赖路径进行更新,使其在子包中运行时也能引用成功。针对不同类型的文件,采取不同的依赖分析手段。
JS 文件:使用 babel.transformFile 修改依赖引用地址
WXSS 文件:使用 postcss.plugin('transform-wxss') 处理依赖的 @import 导入样式文件地址
WXML 文件:使用 require('htmlparser2').Parser 来转换内部 wxs、template(import 和 include 导入)依赖的引用地址
异步分包
小程序基础库版本 2.17.3 及以上开始支持分包异步化,即可以在分包之间互相引用,这个能力可以快速取代我们自己的组件分发方案,而且优化效果更佳,可以将分包中公共依赖的代码部分打成新的分包,在使用时异步按需引入,能力与 Web 端的异步组件类似,但这个方案在生产环境的稳定性有待验证。
实现思路
合并 setData 调用,将其放在下个时间片(事件循环)统一传输,降低通信频率
实现原理
需要先将逻辑层 this.data 进行更新,避免前后数据不一致造成逻辑出错。将需要传送至视图层的 data 进行整合,在 nextTick 中调用原生的 setData 统一进行传送,可以有效降低通信频率,并且在传送前手动做一次与 this.data 的 diff 操作,降低通信体积
1. 降低频率
const nextTick = wx.nextTick ? wx.nextTick : setTimeout; // 小程序里的时间片 API
2. 减少体积
参考京东 Taro 中 diff 的实现,对基本、数组、对象等不同类型进行处理,最终转换为 arr[1]、x.y 这样的属性路径语法,减少传输信息量
实现思路
onLaunch、onLoad 等生命周期函数中存在大量对微信 Storage 的同步调用(使用 Sync 结尾的API),这些操作涉及JS与原生通信,同步等待耗时过久,推迟页面 onReady 触发即用户可交互时间,影响用户体验。直接改为异步操作又存在业务代码改动量较大的问题,存在一定风险,大量的异步回调代码语义不优雅、可读性较差。因此需要对原生 Storage 操作进行重封装,改为对内存中对象的实时存取,提高响应速度,并定期调用原生 API 向真实 Storage 中同步。
实现原理
Kapseln Sie APIs mit konsistenten Aufrufmethoden, mit getStorage und getStorageSync als Basis-APIs. Beim ersten Aufruf wird die native API ausgelöst, um die Originaldaten abzurufen. Alle nachfolgenden Vorgänge werden gespeichert (Löschen, Ändern und Suchen) basieren auf diesem Objekt. Die Set- und Remove-Vorgänge müssen die entsprechenden Daten als Dirty markieren und in einer Dirty-Tabelle speichern, damit die Änderungen später mit dem nativen Ende synchronisiert werden können. Der Aufrufer muss die Änderungssynchronisierungsmethode regelmäßig aufrufen, um die Daten beizubehalten (die Daten in der synchronisierten Dirty-Tabelle zu durchlaufen), um einen versehentlichen Datenverlust zu verhindern, wenn der Speicher ausgeführt wird. Im Allgemeinen muss sie regelmäßig ausgeführt werden (onShow der App führt setInterval aus). und im onHide-Lebenszyklus der App ausgeführt.
Wir haben nicht nur die Speicher-API neu gekapselt, sondern auch einen ähnlichen Ansatz für andere Synchronisierungs-APIs übernommen, die viel Zeit in Anspruch nehmen (z. B. die API getSystemInfo/getSystemInfoSync, die zum Abrufen von Geräte- und Systeminformationen verwendet wird; die zugrunde liegende Implementierung ist synchron ) wird die System-API nur während der ersten Erfassung aufgerufen und das Ergebnis im Speicher zwischengespeichert, und nachfolgende Aufrufe geben die zwischengespeicherten Informationen direkt zurück.
Implementierungsidee
Bevor Sie von Seite A zu Seite B springen, löst das Senden einer Nachricht auf Seite A eine Datenschnittstellenanforderung für Seite B aus und speichert die Ergebnisdaten zwischen Wenn die B-Seite geöffnet wird, rufen Sie zuerst den Cache ab. Wenn die Schnittstelle nicht abgerufen werden kann, rufen Sie die Schnittstelle erneut auf
Implementierungsprinzip
Obwohl die B-Seite nicht instanziiert wurde, wurde die Seite registriert. und der äußere Code der Seite wurde ausgeführt. Daher kann das Veröffentlichen und Abonnieren von Nachrichten mit der Methode der globalen Registrierungsvariable abgeschlossen werden. Implementierungsidee: Wenn die Seite vorab geladen werden muss Nicht im Hauptpaket registriert oder asynchron, es kann nicht über den Veröffentlichungs- und Abonnementmodus ausgeführt werden. Vorab-Anfrage, wir können dies erreichen, indem wir die Vorlademethode global registrieren
ImplementierungsprinzipInitiieren Sie eine Vorab-Anfrage, wenn die Wenn die geladene Seite zum ersten Mal gerendert wird, wird dem Abrufen des Datenergebnisses in der globalen Promise-Variable Vorrang eingeräumt, dann dem Rückruf
5), Speicheroptimierung1, Bildoptimierung
Optimieren Sie die gesamten Bildressourcen (Alibaba Cloud-Funktion)
Webp-Format
: Vollständig wird auf der Android-Seite verwendetDowngraden Sie die folgenden Funktionen in Low -Endmaschinenszenarien
Gif-Animationen werden auf statische Bilder herabgestuftJS- und CSS-Animationen werden auf statische Stile herabgestuft
Zeigen Sie die Swiper-Komponente nicht anVerwenden Sie 60 % QualitätAnwendungsszenarien
Öffentliche Geschäftslogik, z. B. Überprüfung des Benutzeranmeldestatus auf jeder Seite, Erfassung und Verarbeitung von URL-Parametern, automatische PV-Vergrabung, Leistungsüberwachung usw.
ImplementierungsprinzipDie Lebenszyklusfunktion ist ein Plug-In, und die nativen Funktionen onLoad, onShow, onReady und andere werden mithilfe von Object.defineProperty neu geschrieben, um intern eine Promise-Aufgabenkette zu bilden. Durch die Einführung von Plug-Ins kann die Aufgabenkette frei eingefügt werden in der mittleren und vorderen Position, die nacheinander ausgelöst und aufgerufen werden, wenn die Systemlebenszyklusfunktion ausgeführt wird.
Nachdem wir das Plug-in des Lebenszyklus-Hooks implementiert haben, können wir alle Arten der zugrunde liegenden öffentlichen Logik, die verarbeitet werden muss, kapseln und in die Promise-Aufgabenkette des Hosts (nativer Lebenszyklus) einfügen
Ein Satz halbautomatischer Miniprogramm-Erstellungs- und Bereitstellungstools wird basierend auf Miniprogramm CI + Gitlab CI + Puppeteer implementiert. Weitere Informationen finden Sie in meinem anderen Artikel „Automatisierte Bereitstellung von WeChat-Miniprogrammen“. Lösung", Das WeChat-Miniprogramm stellt später miniprogram-ci bereit, das unabhängig in der Linux-Umgebung ausgeführt werden kann, was einfacher und benutzerfreundlicher ist.
Überwachungsfunktionen
Geschäftliche versteckte Punkte (Geschäftliche versteckte Punkte wie Seiten-PV, Modulbelichtung usw.)
Leistungsberichte (mini Programmstart, Seitenrendering, FMP, Speicheralarm)
Ausnahmeüberwachung (JS-Fehler, Schnittstellenfehler, Geschäftsfehler)
Leistungsüberwachungs-Berichtstyp
memory_warning: Speicheralarmdaten Berichterstattung. Erfassungsmethode: Alarmstufen im wx.onMemoryWarning-Rückruf sammeln
app_launch: App-Laufzeitdatenberichterstellung. Erfassungsmethode: Zeichnen Sie die Ausführungszeit des App-Lebenszyklus auf (onLaunch, onShow) und melden Sie sie, wenn die Seite geladen wird
page_render: Berichterstattung über Seitenlaufzeitdaten. Erfassungsmethode: Zeichnen Sie die Ausführungszeit des Seitenlebenszyklus (onLoad, onShow, onReady), FMP usw. auf und melden Sie sie, wenn die Seite onHide oder onUnload ist
Implementierungsprinzip
Basierend auf dem Plug-in-Framework Lösung, die Life-Cycle-Hook-Funktion. Nach dem Umschreiben können Sie Leistungsdaten während der Ausführung des Seitenprogramms automatisch aufzeichnen und melden Weitere Informationen finden Sie in einem weiteren Artikel von
Benutzererfahrungsorientierte Front-End-Leistungsoptimierung4. Zusammenfassende Gedanken und Entwicklungsaussichten
Die Infrastrukturfähigkeiten verbessern sich ständigNeben der Verbesserung der technischen Fähigkeiten erweitert das WeChat-Miniprogramm-Ökosystem auch ständig die Fähigkeitsunterstützung in weiteren Geschäftsszenarien, wie z. B. der Unterstützung von Miniprogrammen zum Teilen von Momenten und der Unterstützung der Generierung von Kurze Links, WeChat-Chat-Material öffnet ein Miniprogramm, um unserem Unternehmen mehr Möglichkeiten und Fantasie zu bieten.
Seit der Geburt der WeChat-Miniprogramme im Jahr 2017 hat sich das Modell der Super-App + Miniprogramme/Light-Anwendungen in verschiedenen Unternehmen wie WeChat und WeChat-Miniprogrammen bewährt. Alipay- und Alipay-Miniprogramme, Douyin- und Douyin-Miniprogramme usw. Miniprogramme, ein Produktmodell mit niedrigen Kosten, schneller Iteration und einfacher Werbung, haben mit der Unterstützung des enormen Datenverkehrs durch Super-Apps in verschiedenen Bereichen große Erfolge erzielt Da es sich bereits allmählich zum Trend entwickelt, fügen immer mehr Unternehmen dieses Modell zu ihren Produkten hinzu. Das Miniprogramm selbst wurde während der Epidemie unwissentlich in jeden Aspekt des Lebens integriert, Gesundheitscodeanwendungen in verschiedenen Regionen, Miniprogrammcodes für E-Commerce-Gruppenkäufe in der Community und Restaurantbestellungen, wenn Sie Milchtee trinken möchten Kaffee, Sie können sie im Voraus über das Miniprogramm herunterladen. Tatsächlich ist das Leben der Menschen untrennbar mit kleinen Programmen verbunden. Die Produkttechnologielösung kleiner Programme hat tatsächlich einen großen sozialen Wert geschaffen.
Als ich mich mit einem Freund unterhielt, sagte ich scherzhaft, dass Mini-Programme PWA-Anwendungen mit chinesischen Merkmalen sind. Auch in Zukunft haben Mini-Programme neben den bestehenden Online-Shopping- und Life-Service-Anwendungen noch großes Potenzial Proportional können sie auch in weiteren Szenarien eingesetzt werden, beispielsweise im Gesundheitswesen, im Offline-Einzelhandel, in Unterhaltungsspielen, in der KI-Intelligenz und in anderen Branchen, in denen die Marktlücke noch lange nicht erreicht ist Das Entwicklungspotenzial von Miniprogrammen ist noch größer. Miniprogramme nähern sich dem ursprünglichen Ziel, Miniprogramme zugänglich und allgegenwärtig zu machen.
Ursprüngliche Adresse: https://juejin.cn/post/7100752247381819399(Teilen von Lernvideos:
Erste Schritte mit dem Web-Frontend)