mark
针对 js 的 WeixinJSCore.invokeHandler 接口提供专门的 C++ 裸绑定接口 InvokeHandler,取出所有参数后,只需要一次 JNI 调用到 nativeInvokeHandler,然后调到具体 API 的 Java 实现函数 Invoke 。
除此之外,针对异步 JsApi 调用,之前的流程是在 java 层抛到另一个线程执行 。有了 libuv Looper 后,优化成在底层起一个 uv 的 worker 线程,通过 ASyncCall 将任务抛到 worker 线程,这样 worker 里只需要执行同步的 api 流程,流程上简化了,效率上比抛 Java 层线程更高 。
2. JsApi 回调优化当框架层需要触发 JS 回调时,之前的做法是拼好一段 JS 字符串然后 evaluate:
evaluateJavascript(String.format( "typeof WeixinJSBridge !== 'undefined' && " + "WeixinJSBridge.invokeCallbackHandler(%d, %s)", callbackId, data));
这里的本质是去调用 JS 里的统一回调处理函数 WeixinJSBridge.invokeCallbackHandler,采取了直接执行一段 JS 的方法 。优点是实现简单,缺点是效率不高 。
因为让 JS 引擎执行一段 JS 代码时,需要先编译,parse 抽象语法树,生成 Ignition 字节码,甚至启用到 TurboFan 编译优化器,最后才真正执行到想调用的 JS 函数 。
同时每个回调都拼一个字符串执行,在 JS 引擎内部会积攒大量临时字符串,占用内存资源 。
优化的方法其实也很简单,就是通过 jsbinding 预先查找好 WeixinJSBridge.invokeCallbackHandler 函数,在需要回调这个 JS 函数时,直接调用即可 。
// 查找到 invokeCallbackHandler 函数后,保存下来mm::JSObject func = JS_GET_AS(mm::JSObject, js_bridge, "invokeCallbackHandler");js_func_holder_ = JS_NEW_OBJECT_HOLDER(func);// ...// 当需要回调时,直接调用JS_CALL(js_func_holder_->Get(), nullptr, nullptr, js_bridge, callbackId, data);
并行调用优化开发者在执行某些耗时较重的任务时,可以使用多线程 Worker,类比标准 H5 的 WebWorker 。
// 主线程初始化 Workerconst worker = wx.createWorker('workers/request/index.js') // 文件名指定 worker 的入口文件路径,绝对路径// 向 Worker 发送消息worker.postMessage({ msg: 'hello worker'})// workers/request/index.js// 在 Worker 线程执行上下文会全局暴露一个 `worker` 对象worker.onMessage(function (res) { console.log(res)})
之前的 Worker 有个限制,只能执行一些纯逻辑运算的代码,不支持 JsApi 的调用 。这很大程度限制了 Worker 的使用,于是我们也在不断的扩展 Worker 的能力,增加了音频、网络、文件等能力 。
// Worker 线程var audio = worker.createInnerAudioContext()audio.src = urlaudio.play()
未来 Worker 将会赋予更多能力,提高开发者并行化处理的效率 。
数据传输优化开发者在 JS 层的数据(ArrayBuffer)需要传到客户端底层,同时客户端底层的数据也需要传到 JS 上层,这中间涉及到数据的高效传输 。在渲染优化时,可以通过 wgfx 提供的 createNativeBuffer 接口,创建一块 JS 和 Naitve 共享的内存,双方可直接读写该内存而无需额外的传输,极大的提高了效率 。
NativeBuffer 的共享内存传输机制,可以应用到多个需要频繁传输数据的场景,比如 Camera 传输的数据、JS 的 WebGL CommandBuffer 传输等等 。
还有一种情况是前面提到的 Worker 之间传输数据,如果通过默认的 postMessage 来传输,效率是非常低的,不利于传输较大的 ArrayBuffer 数据 。为了解决这个问题,我们提供了类似标准 H5 的 SharedArrayBuffer 的能力,用来 Worker 之间高效的传输数据 。
// game.jsconst sab = wx.createSharedArrayBuffer(2)worker.postMessage({ sab})// worker.jsworker.onMessage(function (res) { res.sab.lock(() => { setTimeout(() => { res.sab.unlock() }, 3000) })})
总结【微信小游戏背后的技术优化,可以让所有小游戏获得更好性能】小游戏的性能瓶颈,很大程度局限于 JavaScript,而我们所做的各种优化,是希望能尽量抹平 JavaScript 本身带来的性能损耗,接近并向原生性能靠齐,极具困难和挑战 。
在 IOS 上,我们也为让 JavaScript 拥有 JIT 能力做了深入探索 。同时,我们也在 WebAssembly 上也进行了深入的探索和支持,未来有机会再进行分享 。
推荐阅读
- 微信朋友圈看出人的性格类型
- 女生如何锻炼背部肌肉呢?
- 客厅背景墙颜色风水有讲究
- 家居风水原则不得违背 抵制让人变穷的家居风水
- MySQL索引背后的数据结构及算法原理
- 日本|号称最轻松赚钱方式!日本新奇打工背着电脑走 网友直呼无聊
- 中老年耳背会遗传吗?
- 女性妇科炎症背酸怎么办呢?
- 泰姬陵背后的血腥恐怖袭击 泰姬陵的神秘事件
- 通用搜索引擎背后的技术点