React跨端动态化序章—从JS引擎到RN落地

简介: 介绍 JS 引擎和 RN 技术的落地

一 为什么跨端动态化迫在眉睫

目前很多互联网大厂的移动端开发都在朝着跨端动态化方向发展。由于快速迭代开发或者对原生包体积要求严格,及其对资源成本的把控,实现跨端动态化迫在眉睫。我们先来看看 Native 原生开发的一些不足之处:

  • 1 原生开发周期时间长,审核周期长,会影响到需求发布和迭代效率,有些场景下会更加棘手,比如修复线上紧急 bug ,或者是频繁迭代一些开发需求。

  • 2 目前移动端主要的平台就是 Android 和 iOS,如果一款前端应用想要同时运行在两个平台的话,采用 Native 就需要双端各自开发一遍,这样无疑浪费了资源和提高了维护成本。

  • 3 Native 开发代码要打包在客户端包中,这样增加了包的体积,用户下载的时候,会下载更多的资源,轻量级的包会提高运营效率,而且 Android 和 iOS 应用平台也对包体积严格把控。

说到跨端化方案,首先想到的就是 React Native,为什么这么说呢? 我们往下看。

二 首当其冲的为什么是 React Native

React 在跨端领域也有一席之地,功劳来源跨端方案 React Native,简称 RN ,RN 是目前主流的动态化方案之一,是 Facebook 在 2015 年开源的 JS 框架 React 在原生移动应用平台的跨平台技术,支持安卓和 iOS 平台。

RN 的受欢迎并不仅仅是支持安卓和 iOS 平台,还有一个重要的因素就是动态化,那么这种动态化相比于原生客户端有什么优点呢?

RN 对于原生开发有着明显的优点:

  • 1 RN 是采用运行 React 的 JS 作为开发平台,这样可以让 web 开发者也能够参与到 Native 开发中来,还有就是 RN 让一套代码可以运行在两端,大大减少了开发和维护成本。

  • 2 RN 是采用原生渲染的,性能和体验仅次于 Native 开发。

  • 3 还有一点也是最重要的,就是 RN 是动态化的方案,也就是 RN 打出来的应用包,并不是和 Native 包绑定在一起发布的,而是在运行 Native 的时候拉下 RN 的包,这样一是减少了 Native 包体积,二是 RN 包可以随时发布,提高了迭代效率,也让一些线上问题能够快速解决。

近两年,也有一些兴起的跨端技术方案,比如 Flutter,阿里巴巴开源的 Rax 等,相比这些动态化方法,RN 也有一定优势:

  • 1 生态成熟,技术社区活跃,采用 React 语法,学习成本低。

  • 2 目前业界已经出现了很多成熟方案,比如京东的 JDReact 和美团的 MRN 等。

RN 是基于 React 框架开发的原生应用,React 凭借着 JSX 语法让使用者结合多种设计模式使开发变得非常灵活,React 是 JavaScript (简称 JS ) 框架,那么如果想要运行 RN ,那么就需要运行 JS ,在我们的影响中,JS 作为脚本语言运行到浏览器端,或者运行在 Node.js 中,那么如今却能够作为跨端方案运行到 Native 应用中,这是为什么呢?

原来能够让 JS 运行到 Native 中的法宝就是 JS 引擎,最常见的 JS 引擎就是 v8 ,v8 使用在 Chrome 浏览器和 Node.js 中,构建了 JS 运行时,能够执行 JS 脚本。那么接下来我们就来看一下 RN 中的 JS 引擎。

三 JS 引擎让跨端动态化成为可能

V8 引擎简介

计算机本身并不能读懂编程语言,计算机只能读懂二机制文件,但是为了能够让编程语法能够让计算机读懂,就必须编译成二机制文件,这就是编译语言,比如 JAVA GO 等都是编译型的语言,编译型语法在编译成二机制文件后,会保存二机制文件,在运行时候,可以直接运行二机制文件,不需要重复编译。

还有一类语言,不需要编译成文件,而是需要通过解释器对语言进行动态解释和执行,这类语言就是解释型语言,比如 Python,JS 等。如下图就是两种类型的语言执行过程:

图片1

编译型语言启动需要编译成二进制文件,所以启动速度会比很慢,但是执行的时候是直接使用编译好的二进制文件,所以执行速度会快一些。

但是相比解释型语言,启动会很快,但是执行时候,需要通过解释器解析语法树,变成中间代码,执行字节码,这样就浪费了时间,使得执行速度会变慢。

由于 JS 是解释型语言,它的执行需要宿主环境提供,转成语法树 ,并且读懂语法树,转成字节码并执行的能力,v8 引擎的工作就需要有这些能力:

Parser:将 JS 源码转换成抽象语法树,什么是抽象语法?在计算机科学中,抽象语法树(abstract syntax tree 或者缩写为 AST),或者语法树(syntax tree),是源代码的抽象语法结构的树状表现形式,这里特指编程语言的源代码。

Lgniton:interpreter 解释器,负责将 AST 转换成指令字节码,解释执行指令字节码(ByteCode),解释器执行的时候主要有四个模块:内存中的字节码,寄存器,栈和堆。

TurboFan:compiler 编译器,通过 Lgniton 收集的信息,将指令字节码转换成优化汇编代码。

Orinoco:garbage collector 简称 GC,垃圾回收模块,负责将程序不需要的内存空间回收,提升引擎性能。

如上还有一个问题就是如果每一次都通过 TurboFan 将指令字节码转换成汇编代码,那么这样十分浪费性能。在 v8 出现之前,所有的 JS 虚拟机所采用的都是解释执行的方式,这是 JS 执行速度过慢的主要原因之一。

而 v8 率先引入了即时编译(JIT)的双轮驱动的设计(混合使用编译器和解释器的技术),这是一种权衡策略,给 JS 的执行速度带来了极大的提升。

那么 JIT 就是取编译执行语言和解释执行语言的长处,利用解释器对代码进行处理,对于频率高的代码进行热区收集,在之后指令字节码编译成机器码的时候,储存高频率的二机制机器码,之后就可以复用并执行二机制代码,以减少解释器和编译器的压力。

v8 通过优化后的工作流程如下:

7-4-2.png

知道了 v8 JS 引擎的工作流程之后,那么 RN 应用中用什么 JS 引擎呢?

RN 在 0.60 版本之前使用 JSCore 作为默认的 JS 引擎, JSCore 全名 JavaScriptCore ,JSCore 是 WebKit 默认内嵌的 JS 引擎,JSCore作为一个系统级 Framework 被苹果提供给开发者,作为苹果的浏览器引擎 WebKit 中重要组成部分。

所以在 iOS 应用中默认为 JSCore 引擎,这使得 RN 也用 JSCore ,但是 JSCore 没有对 Android 机型做好适配,在性能,体积,和内存上和 v8 有着明显的差别。

基于这个背景,RN 团队提供了 JSI (JavaScript Interface)框架,JSI 并不是 RN 的一部分,JSI 可以视作一个兼容层,意在磨平不同 JS 引擎中的差异性。

JSI 实现了引擎切换,比如在 iOS 平台运行的 JSCore ,在 Andriod 中运行的是 v8 引擎。

JSI 同样提供了抽象的 API 接口,定义了与各个 JS 引擎交互的接口。

在 JS 中调用 C++ 注入到 JS 引擎中的方法,数据载体格式是通过 HostObject 接口规范化后的,摒弃了旧架构中以 JSON 作为数据载体的异步机制,让 JS 和 C++ 相互感知。

7-4-3.png

明白了 RN 内部运转的背景之后,我们开始正式进入 RN 的世界。

四 走进 React Native 的世界

React Native 将原生开发的最佳部分与 React 相结合, 致力于成为构建用户界面的顶尖 JavaScript 框架。

React Native 开发和传统的 web 端 React 应用开发类似,并且都是 js 语言,使得 web 开发者上手 RN 开发特别简单。

在 React web 应用中,打包,部署到上线的产物,是一个 html ,css,js 文件的集合体,最后把这些产物放在服务器上就可以了。

但是在 RN 中,最后打包产物是一个 js 文件,叫做 jsbundle ,在 Native 端运行 RN 项目,本质上是远程拉取了 jsbundle ,并通过上述的 js 引擎运行当前 jsbundle,每次运行一个 bundle 就需要外层容器提供一个 js 引擎。

在 React 构建的应用为单页面应用,如果存在多个页面,可以通过路由的方式实现页面的跳转,在 RN 中,也有一些解决方案,通常的手段是一个 jsbundle 对应一个页面,或者是一个 jsbundle 对应多个页面,如下图所示:

图四

如果采用,原生 + RN + H5 等融合的技术方案开发的话,单 jsbundle 对应单页面的方式比较适合,但是如果是 Native 作为外层容器,里面都页面都是 RN 的话,单页面多 bundle 也是一个不错的选择。

基础用法

知道了 RN 的本质之后,我们看一下 RN bundle 的注册,在 RN 中每一个应用都有一个入口文件,RN 中提供了注册根本应用的方法,那就是 AppRegistry,这一点和 React web 应用会有一些区别,web 应用中,主要依赖于 react-dom 中提供的 api ,但是在 RN 项目中,无需再下载 react-dom,取而代之的是 react-native 包。

我们先来试着注册一个 RN 应用:

import {
   
   AppRegistry} from 'react-native'
/* 根组件 */
import App from './app' 

AppRegistry.registerComponent('Root', () => <App />)

如上我们注册了 Root ,指向了组件 App。接下来就可以在 App 就可以正常开发了。

在浏览器端,可以用 DOM 标签或者组件,但是在 RN 中是没有 DOM 的,所以如果想要引入原生的视图组件,就必须从 react-native 中引入,下面我们就编写一下 App 组件:

import react from 'react'
import {
   
    View, Text } from 'react-native';

function App(){
   
   
    return <View>
       <Text> Hello,React Native! </Text>
    </View>
}

除了基础的视图容器组件之外,RN 还提供了一些移动端常用的组件,比如列表组件 ScrollView,SectionList 等。

事件

对于一些用户交互事件,RN 中也提供了对应事件组件载体,比如点击事件用的是 TouchableOpacity。 如下所示

function App(){
   
   
    /* 处理点击事件 */
    const handlePress = ()=>{
   
   }
    return <TouchableOpacity onPress={
   
   handlePress} >
        <Text> click </Text>
    </TouchableOpacity>
}

样式

在 RN 中,是没有 css 样式文件的,RN 中的样式就和 CSS IN JS 类似,都是通过 JS 来完成的,RN 提供了 StyleSheet 可以创建 style 对象,如下所示:

import {
   
    StyleSheet, View } from "react-native"

const styles = StyleSheet.create({
   
   
    container: {
   
   
        flex: 1,
        padding: 24,
        backgroundColor: "#eaeaea"
    }
})

function App(){
   
   
    return <View style={
   
   styles.container} >
        样式处理
    </View>
}

对于 RN 的基础使用,如果参考官方文档,学习成本不高,上手也很快。

弄明白 RN 的运行环境和基础使用之后,那么都知道 RN 最终的打包产物只是一个 js 文件,那么这个 js 文件是怎么运行到 native 应用中的,又是怎么和 native 应用进行交互的呢?

接下来文章中我们会对 RN 的原理进行探秘,探索一下 RN 内部运转的机制。

另一方面,现在的动态化方案已经不仅仅是 Android 和 iOS 双端,而是 Android ,iOS ,web ,小程序四端,我们通过 RN 进入到跨端动态化方案上来,研究一下以 React 做 dsl 四端动态化方案的现状与未来。

五 总结

本文从跨端发展现状,再到 RN 运转的本质 JS 引擎,再到 RN 的使用,讲述了移动端动态化的一个落地方案。
如果没有用过 RN 开发过 app 应用的同学,可以尝试跑一下基础 demo 。

相关文章
|
14天前
|
监控 前端开发 JavaScript
React 静态网站生成工具 Next.js 入门指南
【10月更文挑战第20天】Next.js 是一个基于 React 的服务器端渲染框架,由 Vercel 开发。本文从基础概念出发,逐步探讨 Next.js 的常见问题、易错点及解决方法,并通过具体代码示例进行说明,帮助开发者快速构建高性能的 Web 应用。
40 10
|
12天前
|
资源调度 前端开发 数据可视化
构建高效的数据可视化仪表板:D3.js与React的融合之道
【10月更文挑战第25天】在数据驱动的时代,将复杂的数据集转换为直观、互动式的可视化表示已成为一项至关重要的技能。本文深入探讨了如何结合D3.js的强大可视化功能和React框架的响应式特性来构建高效、动态的数据可视化仪表板。文章首先介绍了D3.js和React的基础知识,然后通过一个实际的项目案例,详细阐述了如何将两者结合使用,并提供了实用的代码示例。无论你是数据科学家、前端开发者还是可视化爱好者,这篇文章都将为你提供宝贵的洞见和实用技能。
30 5
|
1月前
|
开发框架 前端开发 JavaScript
React、Vue.js 和 Angular主流前端框架和选择指南
在当今的前端开发领域,选择合适的框架对于项目的成功至关重要。本文将介绍几个主流的前端框架——React、Vue.js 和 Angular,探讨它们各自的特点、开发场景、优缺点,并提供选择框架的建议。
39 6
|
2月前
|
前端开发 JavaScript 开发者
React 和 Vue.js 框架的区别是什么?
React 和 Vue.js 框架的区别是什么?
|
2月前
|
前端开发 JavaScript API
React、Vue.js 和 Angular前端三大框架对比与选择
前端框架是用于构建用户界面的工具和库,它提供组件化结构、数据绑定、路由管理和状态管理等功能,帮助开发者高效地创建和维护 web 应用的前端部分。常见的前端框架如 React、Vue.js 和 Angular,能够提高开发效率并促进团队协作。
87 4
|
28天前
|
JavaScript 前端开发 Java
JS引擎V8
【10月更文挑战第9天】
24 0
|
2月前
|
前端开发 JavaScript 开发者
Express.js与前端框架的集成:React、Vue和Angular的示例与技巧
本文介绍了如何将简洁灵活的Node.js后端框架Express.js与三大流行前端框架——React、Vue及Angular进行集成,以提升开发效率与代码可维护性。文中提供了详细的示例代码和实用技巧,展示了如何利用Express.js处理路由和静态文件服务,同时在React、Vue和Angular中构建用户界面,帮助开发者快速掌握前后端分离的开发方法,实现高效、灵活的Web应用构建。
50 3
|
3月前
|
前端开发 Java UED
JSF 面向组件开发究竟藏着何种奥秘?带你探寻可复用 UI 组件设计的神秘之路
【8月更文挑战第31天】在现代软件开发中,高效与可维护性至关重要。JavaServer Faces(JSF)框架通过其面向组件的开发模式,提供了构建复杂用户界面的强大工具,特别适用于设计可复用的 UI 组件。通过合理设计组件的功能与外观,可以显著提高开发效率并降低维护成本。本文以一个具体的 `MessageComponent` 示例展示了如何创建可复用的 JSF 组件,并介绍了如何在 JSF 页面中使用这些组件。结合其他技术如 PrimeFaces 和 Bootstrap,可以进一步丰富组件库,提升用户体验。
55 0
|
5天前
|
前端开发 JavaScript 开发者
颠覆传统:React框架如何引领前端开发的革命性变革
【10月更文挑战第32天】本文以问答形式探讨了React框架的特性和应用。React是一款由Facebook推出的JavaScript库,以其虚拟DOM机制和组件化设计,成为构建高性能单页面应用的理想选择。文章介绍了如何开始一个React项目、组件化思想的体现、性能优化方法、表单处理及路由实现等内容,帮助开发者更好地理解和使用React。
26 8
|
27天前
|
前端开发
深入解析React Hooks:构建高效且可维护的前端应用
本文将带你走进React Hooks的世界,探索这一革新特性如何改变我们构建React组件的方式。通过分析Hooks的核心概念、使用方法和最佳实践,文章旨在帮助你充分利用Hooks来提高开发效率,编写更简洁、更可维护的前端代码。我们将通过实际代码示例,深入了解useState、useEffect等常用Hooks的内部工作原理,并探讨如何自定义Hooks以复用逻辑。
下一篇
无影云桌面