什么是JS Brige
JS Bridge 是连接 JavaScript 运行环境(如 WebView)与原生客户端(iOS/Android)的通信桥梁,本质是一套跨语言的消息通信方案,让前端代码能调用原生能力(如相机、定位、文件读写),同时原生端也能反向通知前端事件(如页面生命周期、原生按钮点击)。
核心作用:
-
前端调用原生 API:弥补浏览器能力局限(Web 无法直接操作原生硬件 / 系统 API)
-
原生调用前端 JS:原生事件同步给前端(如小程序页面显示 / 隐藏、APP 推送回调)
-
统一跨端通信标准,降低 Hybrid 应用开发成本
流程
-
前端通过 JS Bridge 封装的 API 发送请求(如
bridge.call('takePhoto', { quality: 'high' }, callback)) -
JS Bridge 把请求参数序列化,通过上述方案传递给原生
-
原生解析指令和参数,执行对应原生能力(如调用相机)
-
原生执行完成后,把结果通过 JS Bridge 反向传递给前端
-
前端接收结果,执行回调函数
主流实现方案:
- URL Schema 拦截:
- 前端通过
iframe.src发送jsbridge://action?params格式请求,原生拦截 WebView 的 URL 跳转并解析指令
- 前端通过
- 注入原生对象(Android addJavascriptInterface/iOS evaluateJavaScript)
- 原生在 WebView 初始化时,向 JS 上下文注入一个全局对象(如
window.androidBridge/window.webkit.messageHandlers),前端直接调用该对象的方法
- 原生在 WebView 初始化时,向 JS 上下文注入一个全局对象(如
- Web Message(postMessage)
- 基于
window.postMessage或原生提供的消息通道,实现双向通信
- 基于
扩展思考
-
安全问题:URL Schema 可能被劫持;注入原生对象需避免 XSS 和权限漏洞
-
兼容性:不同系统、不同 WebView 版本的 API 差异处理
-
异步问题:通信是异步的,需要设计回调 / Promise 封装方案
线程通信
线程通信是同一进程内多个线程之间的数据交换和指令传递。前端中,JS 主线程是单线程的,但浏览器 / Node.js 中存在多线程(如渲染线程、JS 主线程、网络线程、Worker 线程),线程通信是多线程协作的基础。
- 主线程 ↔ Web Worker 线程:
postMessage()+onmessage事件监听 - 主线程 ↔ 子线程(Node.js):
child_process的send()/on('message'),worker_threads模块 - 浏览器多线程(渲染线程 / JS 线程 / 网络线程):浏览器内核的消息循环机制
扩展
-
为什么 Worker 不能操作 DOM?:因为 DOM 是渲染线程管理的,JS 主线程和渲染线程是互斥的,Worker 属于独立线程,无法访问渲染线程的资源
-
如何优化线程通信性能?:减少通信频次(批量传输数据)、使用 SharedArrayBuffer 共享内存、避免传递大数据量的非结构化数据
小程序架构
主流小程序采用双线程分离架构(逻辑线程 + 渲染线程),同时结合原生容器层,形成 “原生 + Web” 的混合架构,目的是平衡性能和开发效率,同时保证安全性和管控性。
分工
-
逻辑线程(AppService 线程) :运行 JS 代码(如
app.js、page.js),负责业务逻辑、数据处理、接口请求、生命周期管理;完全隔离 DOM/BOM,不能直接操作界面,通过数据驱动更新视图 -
渲染线程(View 线程) :运行 WXML(模板)和 WXSS(样式),负责页面渲染;本质是一个受限的 WebView(或原生渲染引擎),只能接收逻辑线程传递的数据并渲染
-
原生容器层:提供小程序的基础能力(如底部 Tab、导航栏、弹窗),并通过 JS Bridge 连接逻辑线程和原生客户端,提供相机、定位等原生 API
核心通信机制
-
逻辑线程 ↔ 渲染线程:通过数据传输通道实现,逻辑线程通过
setData方法提交数据变更,数据序列化后传递给渲染线程,渲染线程重新渲染页面;通信是异步的,且有数据大小限制(微信小程序setData单次数据不建议超过 1024KB) -
逻辑线程 ↔ 原生客户端:通过小程序自带的 JS Bridge(如微信的
wx全局对象)实现,前端调用wx.chooseImage等 API 时,底层通过 JS Bridge 转发给原生执行