flutter: 2.0.1
kraken: main@b5574e6
查看源码肯定要带着问题,有针对性的理解不然会陷入代码的汪洋大海中,对于整个仓库有个通观概览的意识,先看成果。运行仓库中的示例代码 (kraken/example/assets/bundle.js) 能够看到生成了 flutter 节点控件:
源码片断如下:
var text1 = document.createTextNode('Hello World!');
var br = document.createElement('br');
var text2 = document.createTextNode('你好,世界!');
p.style.textAlign = 'center';
...
p.appendChild(text1);
于是很天然的,咱们想晓得 js 生成节点如何与 dart 控件对应的;要运行 js 文本那 js 引擎必须筹备好,它是如何初始化的;同时内部传入的 assets/bundle.js
是什么机会读取并传给引擎执行的:
- js 生成节点如何与 dart 控件对应
- js 引擎初始化的机会
- 运行指定 js 文件的机会
概览
从示例利用 (kraken/example/lib/main.dart) 的来看,入口还是绝对清晰的, 间接将 Kraken
对象作为 Scaffold
的 body 主体,接管了参数 assets/bundle.js
作为 bundlePath
的值,跟踪它就解决问题 3。
Kraken
是一个无状态的 Widget, 创立的子控件为 _KrakenRenderObjectWidget
, 它又是一个SingleChildRenderObjectWidget
,这种控件是为了专门绘制单个节点的控件,最重要的 2 个办法:RenderObject createRenderObject(BuildContext context)
创立一个绘制对象;_KrakenRenderObjectElement createElement()
创立控件对应的节点(Element)。
先明析一个概念,前端常常说到 渲染 ,但这里的渲染不是指具体的绘制操作,个别是输入一段 html 文本或者几个 vnode 节点交由浏览器作解析,离绘制还有很长一段距离。flutter 里的RenderObject
(渲染对象) 是真正的绘制,在这里须要有尺寸,内容,色值,画刷等相干的对象去进行绘制操作(离屏幕上呈现绘制内容其实也有不小的间隔),所以为了避免一些名词上的凌乱,一律以绘制代替渲染。
另一个概念是节点 Element,flutter 里的 Element 不辨别 TextNode 也没有显式的 appendChild
操作,也不是 html/xml 文本里说的元素,它由 Widget 创立 (Element createElement()
是 Widget 的形象办法)并且与 Widget 一一对应。
再一个须要回顾的是 flutter 框架如何建设控件节点树相干的一些机制。简而言之,咱们是先得有 Widget 对象,它来创立一个节点(Element), 节点具体做父子关系建设的工作,这样节点树通过各种类型的 Widget 及其 build 办法建设起来,这一步由 flutter 框架实现的,内部不能自己持有节点自行建设层级关系,这一过程叫做挂载(mount)。
所以就能够明确 _KrakenRenderObjectElement
的惟一办法 void mount(Element parent, dynamic newSlot) async {
的作用了。
从 Widget Kraken.build(BuildContext)
到void _KrakenRenderObjectElement.mount(Element parent, dynamic newSlot)
是异步的,两头显然创立了十分多的货色,一步一步来看。
于是按下面的概览总体的分了 4 步:
1 Kraken.build()
_KrakenRenderObjectWidget()
2 _KrakenRenderObjectWidget.createRenderObject
3 _KrakenRenderObjectWidget.createElement
4 _KrakenRenderObjectElement.mount
步骤 1 简直没什么操作,只是生成对象持有内部传入数据
步骤 4 的代码也不多,其实曾经晓得问题 3 的答案了,不确定的话查找一下传入的 _bundlePath
的最终援用,其实就是在 KrakenController.loadBundle
这个办法里。深刻代码再看一下办法调用:
4 _KrakenRenderObjectElement.mount
4.1 KrakenController.loadBundle
KrakenBundle.getBundle
AssetsBundle()
*AssetsBundle.resolve
4.2 _evalBundle
controller.evalBundle()
KrakenBundle.eval
evaluateScripts
_evaluateScripts
'evaluateScripts'
就 2 步 4.1 载入资源 js 文本,具体解析资源的是AssetsBundle
, 基类是KrakenBundle
4.2 调用 js 引擎求值 (evaluate),这里用了个全局办法_evalBundle
,真是匪夷所思的操作,所有对象都在KrakenController
里还搞个全局办法;最终通过 dart 的 ffi 调用了 js 引擎库的办法 'evaluateScripts'
。
于是问题 3 答案近在眉睫:
Kraken 是在挂载节点的时候读取内容,再由 js 引擎执行
问题接踵而至 js 引擎又是何时实现初始化的?