关于浏览器核心的一些思考

在WebKit浏览器上做了4年,主要是一些没有技术含量的port定制和非核心的一些Bug修正什么的。

首先要问,WebKit什么地方是真正比较难的技术壁垒?我认为是3个地方:第一,JavaScript引擎,包含苹果的JavaScriptCore(最新的代码有NB的cssjit和FTL)和Google的v8(上次他做的最大的改善应该是多线程模式的Isolate吧?);第二,WebCore核心layout算法,这个算法麻烦的地方在于它融合了不同的CSS layout,以及那个变态的stacking context,以及需要考虑增量式的CSS样式改变,因此你可以看到一堆的if-else以及消息触发的递归调用,Unicode文本layout也包含在里面,不过我认为像harfbuzz这种“只有极少数人"才能理解的东西不算浏览器的核心,因为它也是一般文本编辑器的核心了;第三,用于GPU硬件加速的Graphics layer树,这部分代码逻辑一方面连接了render树,另一方面又连接着OpenGL相关的buffer、texture操作的API,因此,技术门坎比较高。至于WebKit2以及Chromium的IPC,无非就是数据结构的序列化传递和进程地址空间的隔离呗,无非是为了Web安全、UI交互响应速度考虑,还称不上是浏览器技术的核心。但这些是核心的周边。至于网络、Parser、Web API,那就是周边的周边了。

如果是挑一个来入手,选哪一个?个人觉得容易的还是JavaScript引擎。为什么呢?JS没有C++那种让编译器郁闷死的模板及模板元编程,指令生成什么的,v8是直接生成机器指令,这个有点难度,但JavaScriptCore则只是生成中间指令,所以还好了。而要理解WebCore layout就必须精通W3C CSS规范、DOM事件模型、render树的OOP层次数据结构,如果贸然作出修改,没有运行庞大的回归测试集,你根本无法确信修改是否没有问题。至于Graphics layer树,代码难度没那么高,但是调试也是很不方便的,而且性能上的改进余地估计不大。JS引擎就不一样了:首先它可以单独地分离出来,jsc.exe,命令行运行!那个DOM IDL的JS Bindings其实很干扰人,没必要纠结。甚至JS引擎的GC我看也没必要过分纠结,但是JS本身的性能优化应该还是有东西可以做的:比如说,为不是x86/ARM/MIPS/SH的CPU架构做一个JIT port?改善改善某些特定情形的指令生成?不管怎样,只要能够做出一个来就足以笑傲江湖了,哈哈!

要理解JS引擎,入口点并不在于指令生成,或者是GC对象生命周期管理什么的,而是那个C++栈是如何与JS JIT栈之间是怎么跳来跳去的?在V8的代码术语里,有一个单词比较的形象:Trampoline,英语里“绷床的”的意思,还是有点形象的。

Chromium项目最让人感兴趣的2个声明:将WebCore核心模块化,以及用JS重新实现DOM。前者应可使得WebCore核心layout的代码结构更为清晰,第三方的定制裁剪也将更为方便,后者能,据说去除了罗哩罗嗦的JS-C++ bindings代码能能够进一步提高性能。这第2个目标一则反映了Google guys对他们的V8引擎很有信心,二来我想象不出什么是纯JS的DOM实现,反正听起来很牛B就是了。

我也有一些想法,目前可能还不太成熟,但说无妨吧。

其一,浏览器客户端与人工智能的结合。这是什么意思呢?简单说来,就是观察并模拟人的真实操作,把它们以各种事件的格式记录下来,然后从中抽取模式,并自动形成一个辅助的操作序列的快捷方式。Web服务器将不可能发现是不是真人在使用浏览器。这主要是为了解决某些用户需要重复地点击操作以获取信息所导致的时间浪费而考虑的,目前还有一些困难无法解决,比如那个讨厌的reCAPTCHA。不过,后者目前至少可以使用“廉价人力网络”来解决,据说纯粹的学习也已经能够达到超过一般人的识别正确率了。

其二,基于协作式的浏览器能力协同网络。什么意思呢?简单来说吧,就是UC、Opera提出的网络浏览加速功能,Firefox上也好像有类似的插件?。一个移动设备上的浏览器可能是版本太旧甚至不支持JS,可能是渲染能力有限,或者“流量”能力有限。这个时候怎么办呢?好办,我们在云端架设一个全功能的代理浏览器前端,瘦客户端的移动设备Web浏览器在访问某个网站时,首先将请求URL以及其他的一些会话参数发送到代理服务器,代理服务器在收到请求后,代理整个的加载及渲染过程,然后把渲染结果再发送回移动设备上的浏览器,以达到省流量、提高加载速度(一个真正智能的CDN/Web代理?)等目的。

从技术实现上来说,云端的浏览器可以使用Chromium来架设,但最好是使用PhantomJS那样的headless无UI界面模式。更进一步地,最好是能够把GPU硬件加速渲染后端改为纯软件的,并在ARM CPU上运行(像Baidu那样的,数据中心使用ARM,可以大幅度节省能量)。这前个工作不困难,后个工作还不知道目前Chromium开源部分的代码支持不支持。

这只是技术架构上要做事情的前一半,后一半实际上要更难一点:渲染结果以什么样的格式发送给移动客户端呢?3个思路。一,发送像素格式压缩的图像,比如以png编码什么的;二,发送能够提取矢量及文字信息的图元格式;三,发送仍然是移动客户端能够理解的html格式,但是在其数据及内嵌<img>图片元素上做了进一步的压缩优化。这实际上就是UC在Symbian手机上所做的事情,不过它做的不够好。

这里思路1,2均没啥技术含量,只要在运行时切换WebKit的painter设备类型就可以了,比如切换painter设备为Bitmap,然后把整个render树在上面绘制即可。但是3不同。要做到3的完美的境界,需要将render树反方向序列化为一个DOM树,这个就有点技术含量了。比方说,我们怎么做到把每个render元素都序列化为绝对定位的DOM元素,而且还能够保证在客户端上的整体布局渲染效果与服务器端一模一样?

实际上,把render树看作是一个AST,则上述过程实际上就是AST再到源代码的反汇编优化编译器。它所要做的一些工作如下:去除无效的元素(比如重复的CSS、不显示仅用于分组定位的html元素等等)、保证渲染结果相同基础上CSS layout模式的切换。等等。

还有2个想法,叙述如下:

其一,目前的GPU硬件加速后端似乎不支持“调试”功能,比方说,某些具有CSS3 Transform的页面会出现诡异的黑屏现象,问题很可能出在OpenGL硬件驱动上,但问题是我们不知道原因是什么,很难写出简化的测试用例来重现问题,最后只能是想办法绕过它。我觉得Khronos工作组在这一点上缺乏先见之明,它总是被GPU硬件产商牵着鼻子走(硬件产商可能又是被游戏产商牵着鼻子走,唉,一物降一物!),一个解决方案是使用纯软件来实现硬件GPU的功能,问题是,如果是硬件本身的问题则用软件来模拟来定位不了;另一个是,OpenGL本身没有这样的API来反向跟踪最终屏幕上的fragment像素来自于哪个API输入的vertex数据。

其二,基于WebWorker或WebCL的分布式计算“农场”。这里的一个问题是,如何做到每一个浏览器“农场”上运行的JS代码的热切换?运行时热切换功能是Erlang语言提供的功能,类似于Linux上的SystemTap,它能大大提高系统运行维护的可靠性,做到真正的24×7不间断运行。不过这里的问题实际上解决起来比较简单:做一个Erlang.JS,然后让浏览器“农场”接收到的计算任务就以Erlang语言的代码来编码,传代码而不是仅传数据,配置式的数据仅仅意味着部分的代码灵活性,要彻底的灵活性——也就是系统行为的可演化性,将必须要做到能够将代码作为数据(消息)来传递,而这个就要求目标语言运行环境内嵌语法解析器,C++不支持,但JS/Erlang/LISP这些语言可都是支持的。

你可能感兴趣的:(浏览器,分布式计算,技术架构,硬件加速,javascript引擎)