React跨端动态化之从JS引擎到RN落地详解

目录
  • 一 为什么跨端动态化迫在眉睫
  • 二 首当其冲的为什么是 React Native
  • 三 JS 引擎让跨端动态化成为可能
  • 四 走进 React Native 的世界
  • 五 总结

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

目前很多互联网大厂的移动端开发都在朝着跨端动态化方向发展。由于快速迭代开发或者对原生包体积要求严格,及其对资源成本的把控,实现跨端动态化迫在眉睫。我们先来看看 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 等。如下图就是两种类型的语言执行过程:

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

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

由于 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 通过优化后的工作流程如下:

知道了 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++ 相互感知。

明白了 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 。

以上就是React跨端动态化之从JS引擎到RN落地详解的详细内容,更多关于React跨端动态化JS引擎RN的资料请关注我们其它相关文章!

(0)

相关推荐

  • React组件实例三大属性state props refs使用详解

    目录 一. State 1.概念 2.State的简单用法 3. JS绑定事件 4.react 绑定事件 5.react this指向问题 6.修改state值 7.代码简写 二.props 1.概念 2.传参的基础方法.运算符传参 三.refs 定义 字符串形式的ref.回调函数下ref.createRef 创建ref容器 一. State 1.概念 概念:state是组件对象最重要的属性,值是对象(可以包含多个key:value的组合),组件被称为状态机,通过更新组件的state来更新对应的

  • React特征学习Form数据管理示例详解

    目录 Form数据管理 重置Form状态 form验证 小结 Form数据管理 有时会遇到多个位置需要用户输入的情况,若每个状态都配置state或handler会很繁琐,可以尝试下面的方法 import * as React from 'react'; const LoginForm = () => { // 将多个状态合并为对象 const [state, setState] = React.useState({ email: '', password: '', }); // 通过单个hand

  • React Native可复用 UI分离布局组件和状态组件技巧

    目录 引言 包装 Context.Provider 作为父组件 使用 Context Hook 来实现子组件 使用 React 顶层 API 动态设置样式 复用 Context,实现其它子组件 抽取共同状态逻辑 自由组合父组件与子组件 示例 引言 单选,多选,是很常见的 UI 组件,这里以它们为例,来讲解如何分离布局组件和状态组件,以实现较好的复用性. 假如我们要实现如下需求: 这类 UI 有如下特点: 不管是单选还是多选,都可以有网格布局,我们可以把这个网格布局单独抽离出来,放到一个独立的组件

  • react组件中过渡动画的问题解决

    目录 一.是什么 二.如何实现 CSSTransition SwitchTransition TransitionGroup 一.是什么 在日常开发中,页面切换时的转场动画是比较基础的一个场景 当一个组件在显示与消失过程中存在过渡动画,可以很好的增加用户的体验 在react中实现过渡动画效果会有很多种选择,如react-transition-group,react-motion,Animated,以及原生的CSS都能完成切换动画 二.如何实现 在react中,react-transition-g

  • react Scheduler 实现示例教程

    目录 正文 简单的css动画 etTimeout来实现 循环处理 具体思路 正文 最近在看react源码,react构建fiber树这一块逻辑还比较好理解,但是一旦涉及到任务调度相关的逻辑,看起来是一头雾水.在参考了一些资料和react scheduler源码后,我决定来实现一个简单版的scheduler,相信跟着本文的思路实现一遍,就可以理解为什么react需要有scheduler这个东西来调度任务. 简单的背景知识: 我们知道现在大部分设备的帧率都是60fps,也就是说浏览器每16.7ms会

  • React Native 的动态列表方案探索详解

    目录 背景 技术方案介绍 内存 异常处理 未来规划 背景 时至2022,精细化运营已经成为了各大App厂商的强需求,阿里的 DinamicX.Tangram 大家应该都很熟悉了,很多App厂商也自研了一些类似框架,基于DSL的动态化方案虽然有性能上的一些优势,但是毕竟不是图灵完备,一些需要逻辑动态下发的需求实现成本偏高,或由于DSL本身限制无法实现,针对这个问题我们使用RN进行了一下探索尝试, 利用我们已经相对完善的RN基建,结合客户端列表能力低成本的实现了一套的动态化能力,同时兼顾一定的性能体

  • React跨端动态化之从JS引擎到RN落地详解

    目录 一 为什么跨端动态化迫在眉睫 二 首当其冲的为什么是 React Native 三 JS 引擎让跨端动态化成为可能 四 走进 React Native 的世界 五 总结 一 为什么跨端动态化迫在眉睫 目前很多互联网大厂的移动端开发都在朝着跨端动态化方向发展.由于快速迭代开发或者对原生包体积要求严格,及其对资源成本的把控,实现跨端动态化迫在眉睫.我们先来看看 Native 原生开发的一些不足之处: 1 原生开发周期时间长,审核周期长,会影响到需求发布和迭代效率,有些场景下会更加棘手,比如修复

  • react.js框架Redux基础案例详解

    react.js框架Redux https://github.com/reactjs/redux 安装: npm install redux react-redux #基于react,我们在前面已经安装过了 Redux参考文档: http://redux.js.org/ Redux核心概念:Store 我们可以简单的理解为就是用来存储 各个组件的State或你自己定义的独立的state,对state进行统一读取.更新.监听等操作. http://redux.js.org/docs/basics/

  • 基于js文件加载优化(详解)

    在js引擎部分,我们可以了解到,当渲染引擎解析到script标签时,会将控制权给JS引擎,如果script加载的是外部资源,则需要等待下载完后才能执行. 所以,在这里,我们可以对其进行很多优化工作. 放置在BODY底部 为了让渲染引擎能够及早的将DOM树给渲染出来,我们需要将script放在body的底部,让页面尽早脱离白屏的现象,即会提早触发DOMContentLoaded事件. 但是由于在IOS Safari, Android browser以及IOS webview里面即使你把js脚本放到

  • Node.js+Express配置入门教程详解

    Node.js是一个Javascript运行环境(runtime).实际上它是对Google V8引擎进行了封装.V8引 擎执行Javascript的速度非常快,性能非常好.Node.js对一些特殊用例进行了优化,提供了替代的API,使得V8在非浏览器环境下运行得更好.Node.js是一个基于Chrome JavaScript运行时建立的平台, 用于方便地搭建响应速度快.易于扩展的网络应用.Node.js 使用事件驱动, 非阻塞I/O 模型而得以轻量和高效,非常适合在分布式设备上运行的数据密集型

  • vue服务端渲染页面缓存和组件缓存的实例详解

    vue缓存分为页面缓存.组建缓存.接口缓存,这里我主要说到了页面缓存和组建缓存 页面缓存: 在server.js中设置 const LRU = require('lru-cache') const microCache = LRU({ max: 100, // 最大缓存的数目 maxAge: 1000 // 重要提示:条目在 1 秒后过期. }) const isCacheable = req => { //判断是否需要页面缓存 if (req.url && req.url ===

  • 基于模板引擎Jade的应用(详解)

    有用的符号: | 竖杠后的字符会被原样输出 · 点表示下一级的所有字符都会被原样输出,不再被识别.(就是|的升级版,实现批量) include 表示引用外部文件 短杠说明后面跟着的字符只是一段代码(与|的区别就是,|后面的内容会被显示,而短杠后面的内容直接不显示了!) 例子: js: const jade = require('jade'); console.log(jade.renderFile('./xxx.jade',{pretty:true,name:'singsingasong'}))

  • 用原生 JS 实现 innerHTML 功能实例详解

    都知道浏览器和服务端是通过 HTTP 协议进行数据传输的,而 HTTP 协议又是纯文本协议,那么浏览器在得到服务端传输过来的 HTML 字符串,是如何解析成真实的 DOM 元素的呢,也就是我们常说的生成 DOM Tree,最近了解到状态机这样一个概念,于是就萌生一个想法,实现一个 innerHTML 功能的函数,也算是小小的实践一下. 函数原型 我们实现一个如下的函数,参数是 DOM 元素和 HTML 字符串,将 HTML 字符串转换成真实的 DOM 元素且 append 在参数一传入的 DOM

  • React为 Vue 引入容器组件和展示组件的教程详解

    如果你使用过 Redux 开发 React,你一定听过 容器组件(Smart/Container Components) 或 展示组件(Dumb/Presentational Components),这样划分有什么样的好处,我们能否能借鉴这种划分方式来编写 Vue 代码呢?这篇文章会演示为什么我们应该采取这种模式,以及如何在 Vue 中编写这两种组件. 为什么要使用容器组件? 假如我们要写一个组件来展示评论,在没听过容器组件之前,我们的代码一般都是这样写的: components/Comment

  • js中getBoundingClientRect( )方法案例详解

    一.getBoundingClientRect() 解析 getBoundingClientRect() 方法返回元素的大小及其相对于视口的位置. 语法 rectObject = object.getBoundingClientRect(); 值 rectObject.top:元素上边到视窗上边的距离; rectObject.right:元素右边到视窗左边的距离; rectObject.bottom:元素下边到视窗上边的距离; rectObject.left:元素左边到视窗左边的距离; rect

  • js 实现验证码输入框示例详解

    目录 前言 思路 遇到的问题 HTML CSS JS 前言 验证码输入框应该是很常见的需求吧,不知道各位小伙伴在在遇到的时候是选择找一找插件还是自己动手撸一个呢?我花了点时间撸了一个出来,实际体验还不错,分享给大家. 思路 我在实现之前肯定也是上网搜了一下的,网上的方式大多是使用多个input标签来实现,但我觉得不太优雅,就自己想了一个方法.使用了6个div标签和一个input标签.验证码长度一般是4位或6位,我这里用6位做演示. 先将6个div使用flex布局平铺. 再将input使用绝对定位

随机推荐