Maison  >  Article  >  Applet WeChat  >  Décryptage et réflexion sur la solution d'exécution de l'applet Rax

Décryptage et réflexion sur la solution d'exécution de l'applet Rax

coldplay.xixi
coldplay.xixiavant
2020-11-04 17:45:373083parcourir

La colonne

Tutoriel de développement de programme WeChat Mini présente la solution d'exécution du mini programme Rax.

Décryptage et réflexion sur la solution d'exécution de l'applet Rax

En mars 2020, après avoir pris en charge le schéma de compilation, l'applet Rax a publié une version qui prend en charge le schéma d'exécution. Jusqu'à présent, Rax est toujours le seul petit framework de développement de programmes du secteur qui prend en charge à la fois les solutions de compilation et d'exécution. Cet article vous présentera les principes de la solution d'exécution de l'applet Rax et notre réflexion.

Examen de la solution au moment de la compilation

Avant de présenter la solution au moment de l'exécution, examinons ce qu'est la solution au moment de la compilation. Comme son nom l'indique, la solution de compilation se concentre sur la compilation et le framework représentatif est Taro v2.x. Il convertit JSX dans le langage de modèle du mini-programme (c'est-à-dire WXML/AXML, etc.) via une compilation statique, puis le complète avec du code JS d'exécution léger pour lisser la différence entre le cycle de vie du mini-programme et le cycle de vie de React. , ce qui permet aux utilisateurs de développer de petits programmes avec le React DSL familier. Le principe du schéma de compilation de Rax est similaire à celui de Taro v2.x Pour les détails d'implémentation, vous pouvez vous référer aux articles précédents Analyse du principe du lien Rax vers Mini Program (1) et Analyse du principe du lien. Schéma de compilation du programme Rax Mini. Différente de la solution au moment de la compilation, la solution au moment de l'exécution se concentre sur l'implémentation des capacités de rendu au moment de l'exécution et ne repose pas sur la compilation statique. Par conséquent, il n'y a presque aucune restriction de syntaxe, ce qui constitue sa principale fonctionnalité. Jetons un coup d'œil aux principes de mise en œuvre des solutions d'exécution.

Base de naissance

La mise en œuvre sous-jacente des mini-programmes est en fait basée sur la technologie Web, mais lorsqu'on y réfléchit au niveau du développeur, elle est assez différente du Web. Dans le mini programme, la couche logique et la couche vue sont isolées. La couche logique transmet les données à la couche vue pour déclencher le rendu via la seule méthode setData, et la couche vue déclenche le code de la couche logique via des événements. illustré dans la figure ci-dessous. Par rapport au développement Web, les développeurs peuvent utiliser JS pour appeler l'API DOM/BOM fournie par le navigateur afin de manipuler et de restituer le contenu à leur guise. L'architecture des mini-programmes est plus fermée et plus sûre, mais cela signifie également que le code Web ne peut pas s'exécuter directement. sur les mini programmes.

Décryptage et réflexion sur la solution dexécution de lapplet Rax

Pour les frameworks front-end modernes (React/Vue), la couche inférieure crée essentiellement des vues en appelant l'API DOM. Le modèle de couche de vue du mini-programme doit être écrit par le développeur à l'avance, ce qui signifie que la méthode de création dynamique de DOM n'est pas autorisée dans le mini-programme. Cependant, la fonctionnalité « d'auto-référence » du composant personnalisé du mini-programme ouvre une avancée majeure dans la création dynamique de DOM. Ce qu'on appelle l'auto-référence signifie que le composant personnalisé prend en charge son utilisation comme nœud enfant, ce qui signifie que grâce à la référence récursive, nous pouvons construire n'importe quel niveau et n'importe quel nombre d'arborescences DOM.

Par exemple, supposons que le modèle WXML d'un élément de composant personnalisé d'un petit programme soit le suivant :

<view>  <block>      <element></element>  </block></view><text>  {{r.content}}</text>复制代码

Remarquez que l'élément fait référence à lui-même de manière récursive dans le modèle et termine la récursion par jugement conditionnel. Ensuite, lorsque la couche logique transmet les données suivantes à travers setData :

{
  "nodeId": "1",
  "tagName": "view",
  "children": [
    {
      "nodeId": "2",
      "tagName": "text",
      “content”: “我是?"
    },
    {
      "nodeId": "3",
      “tagName": "text",
      "content": "rax"    }
  ]
}复制代码

La vue finale devient :

<view>
  <text>我是</text>
  <text>rax</text></view>复制代码

De cette façon, nous réalisons intelligemment Fournit la possibilité de restituer dynamiquement des vues basées sur données setData entrantes lorsque le modèle WXML est corrigé. Et c’est la base de la naissance des solutions d’exécution.

Principe de base

La solution d'exécution de Rax est dérivée de kbone, une solution isomorphe pour les mini-programmes et la fin du Web officiellement lancée par WeChat. Les principes de conception de kbone peuvent être renvoyés à l'introduction de son site Web officiel. Un résumé simple consiste à simuler l'API DOM/BOM au niveau de la couche logique, à convertir ces méthodes de création de vues en maintenance d'une arborescence VDOM, puis à la convertir en données correspondant à. setData. Enfin, la vue réelle est rendue récursivement via le modèle prédéfini. Le principe de base du processus depuis l'API DOM jusqu'à la maintenance de l'arborescence VDOM n'est pas compliqué. createElement/appendChild/insertBefore/removeChild et ainsi de suite correspondent aux opérations de base de la structure de données.

Les étudiants qui connaissent Rax doivent savoir que pour prendre en charge plusieurs terminaux, Rax a une conception de pilote. En fait, nous pouvons écrire un autre pilote pour le petit programme et implémenter son API d'interface basée sur les principes ci-dessus. Mais notre choix final a été de compléter l’ensemble du mécanisme de rendu via une API BOM/DOM simulée de niveau inférieur. Les considérations pour cela sont, d'abord, basées sur le développement de kbone, qui est la solution la plus rapide. Le pilote côté applet n'a besoin que de réutiliser le pilote côté Web. Après tout, les document et les variables sont les deux. Cela a été simulé ; deuxièmement, c'est parce que nous souhaitons offrir aux développeurs une expérience de développement plus proche du web. Cette solution signifie qu'en plus d'utiliser JSX, les développeurs peuvent également utiliser directement l'API BOM/DOM pour créer des vues, qui seront plus flexibles. Nous examinons tous les frameworks d'exécution de mini-programmes sur le marché. Remax s'interface directement avec les mini-programmes de la couche VDOM via React-Reconciler (similaire à la conception du pilote de mini-programme Rax mentionnée ci-dessus), tandis que Kbone et Taro 3.0 choisissent tous deux d'utiliser la simulation. .Environnement Web pour implémenter le rendu. Ceci est également lié à l'intention de conception du développeur du framework, et les opinions varient. Le schéma de base de la solution d'exécution de l'applet Rax est le suivant : windowRax 小程序运行时基本原理图

Système d'événements

Dans le runtime de l'applet Rax, la bibliothèque qui simule l'API DOM/BOM est Décryptage et réflexion sur la solution dexécution de lapplet Rax . Les API qu'il prend en charge sont les suivantes :

Décryptage et réflexion sur la solution dexécution de lapplet Rax

En plus du traitement des données de rendu, une autre chose importante est le système d'événements. Il implémente un mécanisme complet de répartition d'événements via la classe de base

. Les nœuds DOM de la couche logique héritent tous de EventTarget et collectent leurs propres événements de liaison via l'unique EventTarget. Chaque composant intégré sur le modèle de couche de vue sera lié à nodeId et écoutera tous les événements déclenchables. Par exemple, une simple balise de vue liera bindtap/bindtouchstart/bindtouchend et d'autres événements. Lorsque l'événement est déclenché, l'identifiant du nœud cible est obtenu via nodeId, puis la fonction correspondante liée par l'utilisateur sur le nœud est déclenchée. event.currentTarget.dataset.nodeId

Conception technique

Le processus principal du projet du runtime du mini-programme Rax suit la conception de Rax Web. Le bundle JS emballé par Webpack côté Web peut être réutilisé dans le runtime du mini-programme. Nous injectons les variables de fenêtre et de document simulées par Décryptage et réflexion sur la solution dexécution de lapplet Rax dans le bundle via le plug-in, puis générons un squelette de projet de mini-programme fixe et chargeons le bundle JS dans app.js. La structure globale de l'ingénierie est présentée dans la figure ci-dessous :

Rax 小程序运行时工程结构

MPA ou SPA ?

La structure ci-dessus est le résultat d'une évolution progressive. Initialement, nous avons utilisé le mode multi-entrées de Webpack pour empaqueter le code de l'applet d'exécution, c'est-à-dire que chaque page serait empaquetée indépendamment sous forme d'entrée. Cela fait que l'applet se comporte davantage comme un MPA. Le problème que cela pose est que le code qui dépend généralement entre les pages n'est pas exécuté dans la même mémoire, ce qui ne correspond pas aux performances de l'applet natif. Cette différence a conduit à notre décision finale de modifier le modèle de packaging du projet. La version actuelle de l'applet d'exécution Rax est plus conforme à la forme SPA et tous les codes commerciaux sont regroupés dans un fichier JS.

Nous avons apporté quelques modifications au lien du package rax-app de l'entrée du projet Rax sur le runtime du mini programme Lors de l'initialisation, il renverra la fonction

de chaque page en fonction du parcours. La render La fonction crée un nœud racine (render), y monte le composant Rax correspondant et ajoute le nœud racine au nœud corps (document.createElement). Pendant le cycle de vie onLoad de chaque page du mini programme, un document.body.appendChild indépendant sera créé et défini comme variable globale, puis sa fonction document correspondante sera appelée pour restituer chaque page indépendamment. render

性能调优

从上面的小程序运行时原理来看,其性能相比原生是存在一定差距的,这主要由以下几个方面造成:第一:逻辑层运行完整的 Rax + 通过模拟 DOM/BOM API 处理 VDOM 并生成 setData 数据,需要消耗更多的计算时间;第二,相比原生小程序需要传递更多 setData 数据,如果容器层数据序列化能力较弱,会大大增加数据传输耗时;第三,视图层通过自定义组件递归动态生成视图,而我们知道递归动作本身就是一个性能损耗点。此外,由于无法预先知晓用户需要绑定的属性和事件,自定义组件模板中只能将所有属性和事件预先绑好,这导致小程序运行过程中会触发很多无用的事件,进一步加重负担。经过我们的 benchmark 计算,在支付宝小程序平台上,运行时小程序框架(包括 Rax/Taro/Remax 等)与原生小程序存在约 40% 的性能差距。

Rax 小程序运行时发布后,经测试其性能相比其他运行时框架存在着较为明显的差距,于是我们启动了性能调优的专项计划。通过以下方面的重构,成功将 Rax 小程序运行时小程序的性能拉升至业界领先水平,与 Taro/Remax 基本处于同一水平线。

  • 更新数据精确化。在旧版本中,setData 的数据是全量更新的,虽然有 dom 子树分割批量更新的设计,但是数据传输仍然存在大量冗余。重构版本中,Rax 增加了节点渲染判断,未挂载节点无须触发更新;将所有更新收拢至顶层 root 节点统一批量处理, 并且通过精确计算数据更新的 path,实现局部更新。比如某次更新节点的 class 属性时,setData 的数据可能是:

    {   "root.children.[0].children.[1].class": "active"}复制代码
  • 内置小程序组件无需维护其属性列表,而是根据用户传参直接赋值。旧版本中,我们维护了所有内置组件的属性,在获取属性值的时候均需要调用 domNode.getAttribute,具有一定性能开销。重构版本 Rax 直接根据用户传参给属性赋值,并将默认值设置的操作移至视图层 WXS/SJS 中处理。

  • 更新 Décryptage et réflexion sur la solution dexécution de lapplet Rax 中的数据结构。经过梳理,Rax 移除了冗余的 tree 数据,重写了 getaElementById 等 API;重构了 attribute、classList 等类;使用了更符合场景需要的 Map/Set 等数据结构,提升了整体的数据处理性能。

  • 渲染模板优化。在支付宝小程序中,Rax 使用 template 进行递归调用;在微信中,Rax 使用 template 调用 element 再调用 template 的形式以避免微信端递归调用 template 的层数限制。在模板中,我们尽量使用 template is 语法进行判断,减少 a:if/wx:if 条件判断,提升模板递归时的性能。

混合使用

无论是出于旧有业务的迁移,或者是出于性能考虑,Rax 小程序运行时中都存在着混合使用的需求。目前,Rax 已经打通与小程序内置组件、小程序自定义组件、小程序页面、小程序插件混合使用的能力。这其中,使用小程序自定义组件是最为复杂的。

与小程序自定义组件混用

在 Rax 中使用小程序自定义组件,其引入路径需要与 usingComponents 保持一致(例如 import CustomComp from '../components/CustomComp/index')。 在编译阶段,Rax 工程使用 Babel 插件进行代码扫描,检测到 JSX 中使用的某个组件是小程序自定义组件(根据其引入路径是否存在同名 axml 文件)时,会将其使用到的属性和事件进行缓存,然后通过 webpack 插件动态生成至递归模板中。在运行时中的创建节点阶段,通过查询缓存判断节点是否为自定义组件。若是自定义组件,则其渲染数据中会插入缓存中的属性,并且绑定事件至该自定义组件实例。

与编译时组件混用(双引擎混合)

通过 Rax 小程序编译时方案产出的组件,从使用形态上来说,可以直接视为小程序自定义组件。而 Rax 工程加强了运行时与编译时的联系,当在 Rax 小程序运行时中使用编译时组件 npm 包时,用户无需引入组件的具体路径,只需像使用普通组件时一样引入,Rax 工程将自动根据该组件 package.json 中是否存在 miniappConfig 字段来判断其是否为一个 Rax 多端组件,然后直接使用其编译时的组件实现。

Orientations d'optimisation futures

Rax est la seule solution de développement de petits programmes du secteur qui prend en charge à la fois les moteurs de compilation et d'exécution. Sa capacité à mélanger deux moteurs permet d'atteindre parfaitement un équilibre entre performances et développement. efficacité. À l'avenir, Rax mettra en œuvre une méthode d'utilisation mixte à double moteur plus flexible, telle que la prise en charge de la désignation d'un composant à compiler avec le moteur de compilation dans un seul projet, offrant ainsi une plus grande flexibilité à l'entreprise.

Résumé

Ce qui précède est l'analyse principale de la solution d'exécution de l'applet Rax. La solution d'exécution résout les limitations de syntaxe inhérentes à la solution de compilation, mais il existe également des contraintes de performances évidentes. On peut dire qu'au stade actuel de 2020, il n'existe toujours pas de solution miracle pour le développement de mini-programmes. Peut-être que la fusion des deux moteurs du mini-programme Rax sera une solution optimale dans une gamme relativement large. Personne ne peut dire jusqu'où peuvent aller les mini-programmes qui vont à l'encontre des normes. Les développeurs devront encore faire face à divers problèmes pendant un certain temps encore. Du point de vue d'un petit cadre de développement de programmes, j'espère seulement que tous les développeurs pourront choisir le cadre le plus approprié pour eux-mêmes et terminer le développement de petits programmes rapidement et efficacement.

Recommandations d'apprentissage gratuites associées : Tutoriel de développement d'applets WeChat

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