iOS 下利用简单代码实现 JS 双引擎功能思路

废话开篇:小程序下有这样的一个概念,就是双引擎,意思就是 UI绘制 跟 JS 执行是在多线程环境下进行的,有人会质疑,JS 不是有异步的方法吗?不管是 setTimeout 还是 promiseiOS 开发下在主线程开辟异步,其实是将异步任务代码块放到了主队列所有任务的最后执行的,那么,它只是调整了执行顺序,并没有开辟线程。JS 也是一样的,JS 本身就是单线程,那么,上面提到的两种方式并没有真正的开辟线程去执行任务,所以,JS 线程下的任务并没有利用 CPU 多核的优势,所有任务还是在一条线程执行的。那么实现类似小程序双引擎下执行任务的思路就是下面例子要体现的。

一、实现效果展示

屏幕录制2021-12-06 下午3.06.14.gif

首先利用 Safari 浏览器的 “开发” 功能,显示出当前应用加载的 WebView

这里效果图可以看到,控制台先打印了 开始异步执行 loadAction 任务,然后就直接执行了 “下一个任务的” 打印,过了 5 秒,控制台才打印 异步执行完成 loadAction 任务。那么,这 5 秒的异步时间是 iOS 原生在异步执行耗时 5 秒的 JS 任务的时间。

二、思路概括

步骤一、 WKWebView 加载本地的一个 H5 页面,然后,在按钮的点击事件里将需要做的耗时事情告诉 iOS 原生

步骤二、iOS 原生收到消息后,创建一个原生下的 JSContext 对象,用来初始化一个 JS 运行环境。

步骤三、JSContext 对象加载本地写好的 JS 文件,然后通过步骤一传进来的参数直接异步调用 JS 文件下对应的 function

步骤四、执行完 JS 文件下对应的 function 后进行返回 iOS 主线程,用 WkWebview 对象执行 H5 页面里的一个固定的回调方法,将数据结果返回至前端页面。

三、代码实现

1、H5 页面

image.png

代码很简单,圈出来的就是通知原生进行异步执行的通知。

在此之前又获得了当前的执行的 Function 名称,当然这里的 id 就是 loadAction,为什么要获取方法名?其实,可以往下看到了 callBack 标注为统一回调的这个 JS 方法,它就是原生在执行完异步任务后要执行的统一回调,这里为了区分是哪个异步方法的调用结果,那么,就返回了之前 JS 获取到的异步方法名,JS 本身就是同步,那么就可以根据规则来接收这些原生返回的数据了。

2、创建有简单耗时任务 JS 文件 main.js

这个 JS 文件就是 JSContext (原生内可提供 JS 虚拟环境的对象)对象要加载 JS 文件,用它来模拟一些耗时的任务。

image.png

doNework:模拟耗时操作

sleep:休眠固定时常(这里写的是5秒)

3、iOS 原生部分

image.png

WKWebView 的初始化方式省略,这里需要注意的是 WKWebView 代理循环引用的问题,可以创建一个中间件避免循环引用

image.png

JSContext 执行 main.js 方法

image.png

这里的 name 参数就是 main.jsdoNework 方法,它其实是由 H5 界面传过来的,这个下面会说。

返回值就是 doNework 方法的返回值,这里返回的就是简单的 “操作成功” 字符串。

WKWebView 代理方法

image.png

对比一下 H5 文件下的 loadAction 方法,

1、对应 WKWebView 代理方法里的 name 标识

2、对应 WKWebView 代理方法里的 body 参数

image.png

对比一下 H5 文件下的 callBack 方法,

image.png

这里可以通过返回数据的 func 的名字判断是哪个异步方法的回调,从而对结果数据进行相应处理

四、总结与思考

这样就实现了 JS 真·多线程,当然,这里也仅仅是个人思路的总结。代码拙劣,大神勿笑。

猜你喜欢

转载自juejin.im/post/7038495447727472676