热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

微信小程序架构分析(中)

本文探讨一下小程序的view模块和service模块是如何构成的。你可以在app.nwappdistweapptplpageFrameTpl.js和app.nwappdist

本文探讨一下小程序的 view 模块和 service 模块是如何构成的。 你可以在app.nw/app/dist/weapp/tpl/pageFrameTpl.js 和app.nw/app/dist/weapp/tpl/appserviceTpl.js 文件内找到页面的模板。

打开微信 web 开发者工具,然后输入 openVendor() 便会打开 WeappVendor这个目录,这里包含了 view 模块和 service 模块使用的几个核心文件:

  • wcc 可执行程序,用于将 wxml 转为 view 模块使用的 js 代码,使用方式为wcc xxx.wxml

  • wcsc 可执行程序,用于将 wxss 转为 view 模块使用的 css 代码,使用方式为 wcsc xxx.wxss

  • WAService.js 提供 service 模块大部分功能,下面会有详细介绍

  • WAWebview.js 提供 view 模块大部分功能,下面会有详细介绍

view 页面详解

view 页面的 template 如下:

 

<html lang="zh-CN"><head>
  <link href="https://res.wx.qq.com/mpres/htmledition/images/favicon218877.ico" rel="Shortcut Icon">
  <meta charset="UTF-8" />
  <meta name="viewport" content=" />

  <script>
    var __webviewId__;
  
script>


  

  

  

  

  

  

  

  

  

  

  

  

  head><body>
  <div>div>body>html>

其中 会在 dev 模式开启后被替换为一个时间锚点,例如:

 

<script>var pageFrameStartTime = new Date();script>

会被 WAWebview.js 内代码替换

到 之间暂时没有被使用到

会被 wcc 命令生成后的 js 代码替换

除了上面这些,页面上还会被插入页面和应用的 style 标签,如:

 

"stylesheet" type="text/css" href="index.wxss">

这里的 wxss 文件包含的是原始 wxss 文件转换后的 css

以及生成 DOM 的启动脚本:

 

<script>
  document.dispatchEvent(new CustomEvent("generateFuncReady", {
    detail: {
      generateFunc: $gwx('./page/index.wxml')
    }
  }))
script>

WAWebview.js 文件中的各个模块(行号为 jsbeautify 之后代码行号,开发者工具版本:092300):

  • 1-77 行: WeixinJSBridge 对象兼容层,这个大概只会在调试时用到,因为开发时和运行时页面都会被后台以注入的方式添加 WeixinJSBridge 这个对象。我们可以通过这段代码看到它暴露的方法: invoke invokeCallbackHandleron publish subscribe subscribe subscribeHandler。

  • 78-235 行:Reporter 对象,它的作用就是发送错误和性能统计数据给后台

  • 236-596 行:wx 对象,页面的核心之一,一方面封装 WeixinJSBridge 的 invokeMethod 方位为易于调用的形式(例如 redirectTo, navigateTo等),另一方面封装 WeixinJSBridge 回调方法,调用者可以使用wx.onAppDataChange(callback) 添加数据变更的回调函数,最后提供wx.publishPageEvent 发送页面事件到后台

  • 607-1267 行:wxparser 对象,提供 dom 到 wx element 对象之间的映射操作,提供元素操作管理和事件管理功能

  • 1268-1285 行:转发 window 上的 animation 和 transition 相关的动画事件到 exparser

  • 1286-1313 行:订阅并转发 WeixinJSBridge 提供的全局事件到 exparser

  • 1324-1345 行:转发 window 上的 error 以及各种表单事件到 exparser

  • 1347-3744 行:使用 exparser.registerBehavior 和exparser.registerElement 方法注册各种以 wx- 做为标签开头的元素到 exparser

  • 3744-4498 行:virtual dom 渲染算法实现,提供 diff apply render 等方法,该模块接口基本与 virtual-dom 一致,这里特别的地方在于它所 diff 和生成的并不是原生 DOM,而是各种模拟了 DOM 接口的 wx element 对象

  • 4599-4510 行:插入默认样式到页面

从页面 data 到 dom 的主要流程如下:

 

var vtreevar rootNodedocument.addEventListener("generateFuncReady"function(e{
  var generateFunc = e.detail.generateFunc;
  wx.onAppDataChange(function(obj{
    // 合并 data 到现有 data
    DataStore.setData(obj.data)
    // 生成 virtual dom 的 Javascript plain object
    var props = generateFunc(DataStore.getData())

    // 第一次渲染
    if (obj.options.firstRender) {
      vtree = createVirtualTree(props, true)
      rootNode = vtree.render()
      rootNode.replaceDocumentElement(document.body)
      wx.initReady()
    } else {
      var other_vtree = createVirtualTree(props, false)
      var patches = vtree.diff(other_vtree)
      patches.apply(rootNode)
      vtree = other_vtree
      document.dispatchEvent(new CustomEvent("pageReRender", {}));
    }
  })})

上面的 DataStore 对象提供合并和获取当前页面 data 对象的功能,其实现如下:

 

var DataStore = (function() {
  var data = {}
  return {
    getData: function() {
      return data
    },
    setData: function(e) {
      for (var t in e) {
        for (var n = (0, parsePath)(t), o = data, a = void 0, s = void 0, c = 0; c < n.length; c++) Number(n[c]) === n[c] && Number(n[c]) % 1 === 0 ? Array.isArray(o) || (a[s] = [], o = a[s]) : "[object Object]" !== Object.prototype.toString.call(o) && (a[s] = {}, o = a[s]), s = n[c], a = o, o = o[n[c]];
        a && (a[s] = e[t])
      }
    }
  }})()// 解析 key 为 data 内对象的路径字符串function parsePath(e) {
  for (var t = e.length, n = [], i = "", r = 0, o = !1, a = !1, s = 0; s < t; s++) {
    var c = e[s];
    if ("\\" === c) s + 1 < t && ("." === e[s + 1] || "[" === e[s + 1] || "]" === e[s + 1]) ? (i += e[s + 1], s++) : i += "\\";
    else if ("." === c) i && (n.push(i), i = "");
    else if ("[" === c) {
      if (i && (n.push(i), i = ""), 0 === n.length) throw new Error("path can not start with []: " + e);
      a = !0, o = !1
    } else if ("]" === c) {
      if (!o) throw new Error("must have number in []: " + e);
      a = !1, n.push(r), r = 0
    } else if (a) {
      if (c < "0" || c > "9") throw new Error("only number 0-9 could inside []: " + e);
      o = !0, r = 10 * r + c.charCodeAt(0) - 48
    } else i += c
  }
  if (i && n.push(i), 0 === n.length) throw new Error("path can not be empty");
  return n}

可以看到,每次 data 变化之后,小程序就会开始整个页面的 diff patch 过程。

对于原生实现的组件, exparser 会在监视到数据变化后发送对应事件到 WeixinJSBridge。

service 页面详解

service 页面会被被拼接为以下的样子:

 

<html><head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <link href="https://res.wx.qq.com/mpres/htmledition/images/favicon218877.ico" rel="Shortcut Icon">
  <script>
  var __wxAppData = {}
  var __wxRoute
  var __wxRouteBegin
  
script>
  <script>var __wxConfig = {"pages":["page/index"],
  // app 相关各种配置
  }
script>
  <script src="http://70475629.appservice.open.weixin.qq.com/asdebug.js">script>
  <script src="http://70475629.appservice.open.weixin.qq.com/WAService.js">script>
  <script src="http://70475629.appservice.open.weixin.qq.com/app.js">script>
  <script>
    __wxRoute = 'page/index';
    __wxRouteBegin = true
  
script>
  <script src="http://70475629.appservice.open.weixin.qq.com/page/index.js">script>head><body>
  <script>
    window._____sendMsgToNW({
      sdkName: 'APP_SERVICE_COMPLETE'
    })
  
script>body>html>

除了配置和开发者编写的页面、app.js,页面还在加载了 asdebug.js 和 WAService.js 两个文件。

asdebug.js 文件位于 nwjs 项目目录下,路径为app/dist/weapp/appservice/asdebug.js。 它包含了两个部分,一个是 WeixinJSBridge 针对 service 模块的实现,另一块是一些方便命令使用的接口, 例如:help() 会告诉你一些可用的函数:

该文件只会在开发者工具内被引入,如果小程序在微信内运行,应该会由微信底层提供 WeixinJSBridge。

WAService 负责 service 模块的一些核心逻辑,它包含以下部分 (行号为 jsbeautify 之后代码行号,开发者工具版本:092300):

  • 1-78 行: 跟 WAWebview.js 一样的 WeixinJSBridge 兼容模块

  • 79-245 行: 跟 WAWebview.js 一样的 Reporter 模块

  • 246-1664 行:比 WAWebview.js 中 wx 功能更为丰富 wx 接口模块

  • 1665-2304 行:appServiceEngine 模块,提供 Page,App,GetApp 接口

  • 2305-2360 行: 为 window 对象添加 AMD 接口 require define

现在的 WAService 还有有很多地方依赖 window 对象,所以很有可能它在微信中和开发者工具内一样,依然运行于 webview 标签之内。

下篇介绍如何自己动手建立一个可以运行小程序的环境,欢迎关注。

 

原文转自: 乐搏学院http://www.learnbo.com/
推荐阅读
  • 本文详细介绍了Java代码分层的基本概念和常见分层模式,特别是MVC模式。同时探讨了不同项目需求下的分层策略,帮助读者更好地理解和应用Java分层思想。 ... [详细]
  • 网站访问全流程解析
    本文详细介绍了从用户在浏览器中输入一个域名(如www.yy.com)到页面完全展示的整个过程,包括DNS解析、TCP连接、请求响应等多个步骤。 ... [详细]
  • Python 数据可视化实战指南
    本文详细介绍如何使用 Python 进行数据可视化,涵盖从环境搭建到具体实例的全过程。 ... [详细]
  • MySQL的查询执行流程涉及多个关键组件,包括连接器、查询缓存、分析器和优化器。在服务层,连接器负责建立与客户端的连接,查询缓存用于存储和检索常用查询结果,以提高性能。分析器则解析SQL语句,生成语法树,而优化器负责选择最优的查询执行计划。这一流程确保了MySQL能够高效地处理各种复杂的查询请求。 ... [详细]
  • 浏览器作为我们日常不可或缺的软件工具,其背后的运作机制却鲜为人知。本文将深入探讨浏览器内核及其版本的演变历程,帮助读者更好地理解这一关键技术组件,揭示其内部运作的奥秘。 ... [详细]
  • 本文详细探讨了几种常用的Java后端开发框架组合及其具体应用场景。通过对比分析Spring Boot、MyBatis、Hibernate等框架的特点和优势,结合实际项目需求,为开发者提供了选择合适框架组合的参考依据。同时,文章还介绍了这些框架在微服务架构中的应用,帮助读者更好地理解和运用这些技术。 ... [详细]
  • 本文详细解析了 Yii2 框架中视图和布局的各种函数,并综述了它们在实际开发中的应用场景。通过深入探讨每个函数的功能和用法,为开发者提供了全面的参考,帮助他们在项目中更高效地利用这些工具。 ... [详细]
  • 三周学会小程序第七讲:提交问题
    截止到上一讲可以支持数据库存储了,所以这一讲开始讲解怎么从小程序发布一个问题并存储到服务器端。下面简单罗列一下本讲的知识点。对了老规矩,文末附源码。对小 ... [详细]
  • 为什么多数程序员难以成为架构师?
    探讨80%的程序员为何难以晋升为架构师,涉及技术深度、经验积累和综合能力等方面。本文将详细解析Tomcat的配置和服务组件,帮助读者理解其内部机制。 ... [详细]
  • Ext JS MVC系列一:环境搭建与框架概览
    本文主要介绍了如何在项目中使用Ext JS 4作为前端框架,并详细讲解了Ext JS 4的MVC开发模式。文章将从项目目录结构、相关CSS和JS文件的引用以及MVC框架的整体认识三个方面进行总结。 ... [详细]
  • 秒建一个后台管理系统?用这5个开源免费的Java项目就够了
    秒建一个后台管理系统?用这5个开源免费的Java项目就够了 ... [详细]
  • DVWA学习笔记系列:深入理解CSRF攻击机制
    DVWA学习笔记系列:深入理解CSRF攻击机制 ... [详细]
  • 深入解析Struts、Spring与Hibernate三大框架的面试要点与技巧 ... [详细]
  • 微信小程序实现类似微博的无限回复功能,内置云开发数据库支持
    本文详细介绍了如何利用微信小程序实现类似于微博的无限回复功能,并充分利用了微信云开发的数据库支持。文中不仅提供了关键代码片段,还包含了完整的页面代码,方便开发者按需使用。此外,HTML页面中包含了一些示例图片,开发者可以根据个人喜好进行替换。文章还将展示详细的数据库结构设计,帮助读者更好地理解和实现这一功能。 ... [详细]
  • JVM参数设置与命令行工具详解
    JVM参数配置与命令行工具的深入解析旨在优化系统性能,通过合理设置JVM参数,确保在高吞吐量的前提下,有效减少垃圾回收(GC)的频率,进而降低系统停顿时间,提升服务的稳定性和响应速度。此外,本文还将详细介绍常用的JVM命令行工具,帮助开发者更好地监控和调优JVM运行状态。 ... [详细]
author-avatar
1237i
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有