phodal / articles

Article Publish in Wechat & Toutiao
http://articles.phodal.com/
Creative Commons Zero v1.0 Universal
912 stars 119 forks source link

「微信小程序」剖析(四):原生的实时DOM转Virtual DOM #30

Open phodal opened 7 years ago

phodal commented 7 years ago

在之前的几篇文章里,我们讨论了MINA的一些原理。晚上在想着怎么结合Vux + Virtual Dom实现一个名为WINV框架的时候,在探索WCC功能才发现:自己又忽略掉了一个很重要的性能优化细节。这个WCC如果内置在浏览器里,就是可以实时的将DOM转换为以JSON表示的DOM。

先将DOM转换为Virtual Dom,再转换回去的优点是可以分离数据和样式。这也就是为什么React的学习成本高的原因之一了。

Virtual Dom的表现形式

为了将真实的DOM转换为Virtual DOM,我们需要将DOM以一定的形式保存下来,如MINA的:

<map longitude="23.099994" latitude="113.324520" markers="{{markers}}" covers="{{covers}}" style="width: 375px; height: 200px;"></map>

如:

{
    "attr": {
        "covers": "",
        "latitude": "113.324520",
        "longitude": "23.099994",
        "markers": "",
        "style": "width: 375px; height: 200px;"
    },
    "children": [],
    "tag": "wx-map"
}

又或者是React中的:

{"type":"ul","key":null,"ref":null,"props":{"className":"my-list","children":{"type":"li","key":null,"ref":null,"props":{"children":"Text Content"},"_owner":null,"_store":{}}},"_owner":null,"_store":{}}

当然我们也可以自己实现一个比较简单的DOM转为Virtual DOM,如将

  var newDiv = document.createElement("div"); 
  var newContent = document.createTextNode("Hi there and greetings!"); 
  newDiv.appendChild(newContent); //add the text node to the newly created div. 

转换为接近原生的:

{"nodeType":1,"tagName":"div","attributes":[],"childNodes":[{"nodeType":3,"nodeName":"#text","nodeValue":"Hi there and greetings!","childNodes":[]}]}

原生的Parser与JS Parser

我会假装你已经知道了浏览器相关的很多细节,我也假装我已经对这些细节很清晰。下图一份Webkit浏览器的早期架构图:

如果我们使用JS实现一个将WXML将换为DOM JSON,我们就需要间接通过JavaScript Engine(即JSCore )来转换这个JSON文件。当有大量的DOM的时候,这就不是一件轻松的事了。所以,在WCC的生成代码里对DOM的数量限制为16000

我们可以用原生的接口来将WX DOM转换为JSON,但是我们没有办法用原生的接口来将DOM JSON转换DOM——毕竟我们还有大量的数据和绑定函数。

而这一点对于混合应用来说,就特别有帮助:

如果这个插件可以用在Cordova上,那么它将改善混合应用的性能。

数据绑定

当我们触发了generateFunc方法的时候:

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

我们调用下面的方法去初始化我们的DOM,并把数据传输进去:

var node = generateFunc((0, DataClass.getData)());

函数绑定

MINA的函数绑定机制是由函数名来决定的,如:

"bind" === propKey.slice(0, 4) ? createEventHandle(domElement, propKey.slice(4), propValue);
"catch" === propKey.slice(0, 5) ? createEventHandle(domElement, propKey.slice(5), propValue, !0);
"on" === propKey.slice(0, 2) ? createEventHandle(domElement, propKey.slice(2), propValue);

对于其他类型的绑定则是:

"style" === propKey ? domElement.setAttribute(propKey, (0, r.transformRpx)(propValue)) : domElement.setAttribute(propKey, propValue)
  - "animation" === propKey && "object" === ("undefined" == typeof propValue ? "undefined" : i(propValue)) && propValue.actions && propValue.actions.length > 0 && !function() {})

PS:我突然就不想看这个if else经过minify以后的代码了,太恶心了。。。

如,我们的wxml:

<view  bindtap="bindViewTap" class="userinfo"></view>

我们的propKey是bindtap,我们的propValue是bindViewTap,随后我们就会根据当前的函数名去创建相应的事件。

微信小程序」剖析系列

dingyiming commented 7 years ago

赞!

phodal commented 7 years ago

@dingyiming 好快~~,我的文章还没排版好呢。

dingyiming commented 7 years ago

@phodal 哈哈,刚巧,刚刚看到自己github动态第一条就是你的文章

hzuhyb commented 7 years ago

一棵探索的心

gantoday commented 6 years ago

image 请问这里的dom是怎么得到的呢? 萌新没看懂。

NoraGithub commented 6 years ago

我们可以用原生的接口来将WX DOM转换为JSON,但是我们没有办法用原生的接口来将DOM JSON转换DOM——毕竟我们还有大量的数据和绑定函数。 我们可以通过修改这个JSON来间接达到修改dom的目的吗?这里说的原声接口是哪个呢?没找着 T_T

phodal commented 6 years ago

@NoraGithub 理论上是可以的,但是成本比较高。就是 wxss 命令

NoraGithub commented 6 years ago

@phodal 谢谢答复。我再研究下。

wind4gis commented 6 years ago

额,我现在没法看到楼主写的源码,现在开发者工具下的JS文件全都做了混淆处理,变量名也被简写了。。。现在没法看到里边的运行逻辑。。。