ReactLynx 编程思想
ReactLynx 遵循 React 的编程模型,但通过利用 Lynx 提供的双线程运行时,结合自身的编程范式(或规则)来实现更好的性能和用户体验。
你的代码运行在两个线程上
当组件 <HelloComponent /> 被渲染时,你可能会在控制台看到 "Hello" 被打印两次。
这是因为它的代码会在两个线程上运行:主线程和后台线程,它们都是 Lynx 双线程运行时的一部分。
- 主线程负责渲染初始界面和应用后续的 UI 更新。 这使得用户能尽快看到第一屏内容,同时减轻主线程的负担。
- 后台线程运行完整的 React 运行时,负责处理组件的生命周期和其他副作用。由于无法完全与单线程 React 保持一致,我们有一个修改后的组件生命周期,详见组件生命周期。
并非所有代码都能在两个线程上运行
然而,并非所有代码都能在两个线程上运行。
考虑以下向 GlobalEventEmitter 添加监听器的示例:
当组件 <EventListenerComponent /> 被渲染时,你会看到 "not a function" 的错误。这是因为 lynx 在两个线程渲染了这个组件,但实际上 lynx.getJSModule('GlobalEventEmitter') 不能在主线程执行。
❓ 为什么会出现这个 错误?
这仍然与 Lynx 的双线程运行时架构有关,<EventListenerComponent /> 的代码会在两个线程上执行:
-
对于后台线程:
lynx.getJSModule函数是 LynxGlobalEventEmitterAPI 的一部分。因此,在这里执行lynx.getJSModule('GlobalEventEmitter')不会有问题。 -
对于主线程:
相反,
getJSModule函数在主线程上并不存在。因此,当这段代码在主线程上执行时,lynx.getJSModule会被判定为undefined,导致 "not a function" 错误。
某些代码只能在后台线程运行
通常渲染无关的副作用不能在主线程执行,如数据更新、事件监听、定时器、网络请求等。 在主线程执行这些副作用会导致运行时错误。 我们称这种只会在后台线程被执行的代码为 后台专属(background only) 代码。 通过标注后台专属代码,我们能够帮助编译器更好地优化代码,并避免在主线程执行这些副作用。
后台专属代码有以下关键规则:
规则一:满足这些条件之一的代码被视为后台专属代码
Lynx 默认将满足这些条件之一的代码视为后台专属代码:
- 事件处理器(如
bindtap/catchtap) - Effect(如
useEffect/useLayoutEffect) ref属性和useImperativeHandle- 标注
'background only'指令的函数 - 标注
import 'background-only'指令的模块
例如,以下示例中所有这些内含 console.log 的函数都被视为后台专属的。这些函数既不会被打包进主线程代码中,也不会在主线程执行。
遵循这个规则,我们可以知道刚才的 <EventListenerComponent /> 应该把使用 GlobalEventEmitter 的代码移到 useEffect 中。
这样可以确保这部分代码只在后台线程上运行,在那里可以访问到 GlobalEventEmitter API:
规则二:后台专属代码只能在其他后台专属代码中使用
当涉及到依赖关系时,情况会变得更复杂。 简单来说,后台专属代码只能被其他后台专属代码调用。
规则三:只被后台专属代码使用的代码被视为后台专属
通常,元件的事件 回调函数会被视为后台专属的。handleTap 虽然没有标记 'background only' 指令,但会被视为后台专属代码,因为它仅在 bindtap 事件中作为处理器被调用。
backgroundOnly 函数也会被视为后台专属的,因为它只在 useEffect 的回调函数中被调用。