平时使用WebStorm或VSCode对RN工程中的文件修改后,在键盘上按一下快捷cmd+s进行文件保存,此时当前调试的RN页面就会自动进行刷新,这是RN开发相比于原生开发一个很大的优点:热更新。
那么,从按一下快捷cmd+s到RN页面展示出最新的JS页面,这个过程是怎样发生的呢?下面根据时间顺序来梳理一下。
这里约定后面说的原生部分是指iOS端,ReactNative源码分析指的是iOS端集成的RN框架分析。
 
原生APP中RN页面的热更新简要流程
React Native应用包含两部分:原生代码和JavaScript代码。JavaScript和原生代码通信的桥梁是Bridge,而Bridge的实现又依赖于JSThread的runloop。
当JS有消息要传递给原生时,它会把消息封装成事件放入到JSThread的runloop的事件队列中,而JSThread的runloop会监听消息队列中的事件,一旦有事件需要处理,就会将其交给Bridge处理,从而实现JavaScript和原生代码的相互调用和数据传输。
 
基于JavaScript和原生代码的消息传递机制,RN热更新步骤如下:
1.在iOS原生中的RN页面触发热更新时,首先是JS环境中的websocket收到了Metro服务器的通知,在这个通知中包含了需要更新的JS bundle的URL地址,然后js将这个通知事件放到了JSThread的runloop中传到了RCTCxxBridge。
2.RCTCxxBridge收到热更新事件后,调用JavaScriptCore框架中的方法来执行一个JavaScript脚本,这个脚本会告诉JavaScript环境去下载新的JS bundle并执行它。事件又回到了JS。
3.JavaScript环境调用下载命令向远程服务器请求新的JS bundle,事件又被转回到了原生侧。
4.原生侧下载最新的bundle.js,下载完成后调用加载,执行js方法。
5.重新设置RN页面的根组件。
 
热更新触发条件
React Native在调试模式下有两种热更新方式:Hot Reloading和Live Reload。Hot Reloading可以实现代码的增量更新,而Live Reload技术则是全量更新。
下面以在index.js中新增一个组件注册语句为例。
在RN项目中index.js是ReactNative项目的入口文件,RN启动时首先会执行这个文件,把组件注册到AppRegistry中,这里在index.js的文件底部顺序添加一个组件注册,然后按快捷键cmd+s保存修改
AppRegistry.registerComponent('FlatListDemo', () => FlatListDemo);
这时本地的Packager服务会监听本地文件系统的变化,当有文件修改并保存时,Packager会运行RN命令行工具,自动生成一个新的bundle文件
react-native bundle --platform ios --dev false --entry-file index.js --bundle-output ios/main.jsbundle --assets-dest ios
然后将生成的bundle文件上传至服务器,接着Metro 服务器通过 WebSocket 链接发送消息给APP应用程序。

触发热更新

在APP中RN框架启动时,会在APP的JS运行上下文中创建一个websocket链接并与js服务器建立连接,它用于监听Metro服务器发来的bundle.js更新通知。
当Packger打了新的bundle.js并上传到js服务器后,Metor服务器就会向与它链接的websocket发送更新通知,js引擎收到服务器的通知后,就会做后续的事件处理。
具体js建立websocket的代码如下:

在iOS端ReactNative框架中,RCTCxxBridge文件中的+ (void)runRunLoop方法内负责创建并运行JS引擎对应的jsThread的runloop。它在APP启动时被创建,用来处理js引擎的任务和事件,并保证了_jsThread的常驻,不被销毁。
runloop被注册时机在RN框架启动时:
js引擎收到服务器的通知后,被包成一个原生runloop的事件源放入到事件队列中,然后jsThread的runloop开始处理事件。
然后把事件加入到RCTMessageThread中进行异步处理
RCTCxxBridge调用js脚本,让js处理与最新bundle.js下载相关的事件。把事件传入到js事件队列中
js引擎处理完JS层面的事件后,将事件转回给原生,让原生代码执行实际的下载工作
原生侧的RCTDevSettings模块的reloadWithReason:方法进行处理。调用ReloadCommand监听的触发器,进行触发reloadCommand命令
RCTReloadCommand发送didReceiveReloadCommand收到下载指令
接着调用RCTBridge中的didReceiveReloadCommand方法,RCTBridge中销毁之前的js缓存,调用setUp进行js环境重置,js资源下载
js资源下载完成后,执行js代码
js资源reload完成后,调用js引擎,展示目标组件

当js文件加载成功后,APP会重新创建一个RCTRootContentView, 并将旧的移除,把新的添加上去。新的RCTRootContentView.reactTag使用规则递增
- (void)bundleFinishedLoading:(RCTBridge *)bridge
{
RCTAssert(bridge != nil, @"Bridge cannot be nil");
if (!bridge.valid) {
return;
} [_contentView removeFromSuperview];
_contentView = [[RCTRootContentView alloc] initWithFrame:self.bounds
bridge:bridge
reactTag:self.reactTag
sizeFlexiblity:_sizeFlexibility];
[self runApplication:bridge]; _contentView.passThroughTouches = _passThroughTouches;
[self insertSubview:_contentView atIndex:0]; if (_sizeFlexibility == RCTRootViewSizeFlexibilityNone) {
self.intrinsicContentSize = self.bounds.size;
}
} - (void)runApplication:(RCTBridge *)bridge
{
NSString *moduleName = _moduleName ?: @"";
NSDictionary *appParameters = @{
@"rootTag" : _contentView.reactTag,
@"initialProps" : _appProperties ?: @{},
}; RCTLogInfo(@"Running application %@ (%@)", moduleName, appParameters);
[bridge enqueueJSCall:@"AppRegistry" method:@"runApplication" args:@[ moduleName, appParameters ] completion:NULL];
}

至此,APP中RN页面的热更新主要流程结束。

 

APP中RN页面热更新流程-ReactNative源码分析的更多相关文章

  1. SpringMVC执行流程及源码分析

    SpringMVC流程及源码分析 前言 ​ 学了一遍SpringMVC以后,想着做一个总结,复习一下.复习写下面的总结的时候才发现,其实自己学的并不彻底.牢固.也没有学全,视频跟书本是要结合起来一起, ...

  2. Struts2请求处理流程及源码分析

    1.1 Struts2请求处理 1. 一个请求在Struts2框架中的处理步骤: a) 客户端初始化一个指向Servlet容器的请求: b) 根据Web.xml配置,请求首先经过ActionConte ...

  3. Servlet容器Tomcat中web.xml中url-pattern的配置详解[附带源码分析]

    目录 前言 现象 源码分析 实战例子 总结 参考资料 前言 今天研究了一下tomcat上web.xml配置文件中url-pattern的问题. 这个问题其实毕业前就困扰着我,当时忙于找工作. 找到工作 ...

  4. Android应用层View绘制流程与源码分析

    1  背景 还记得前面<Android应用setContentView与LayoutInflater加载解析机制源码分析>这篇文章吗?我们有分析到Activity中界面加载显示的基本流程原 ...

  5. django Rest Framework----APIView 执行流程 APIView 源码分析

    在django—CBV源码分析中,我们是分析的from django.views import View下的执行流程,这篇博客我们介绍django Rest Framework下的APIView的源码 ...

  6. DRF认证流程及源码分析

    认证 前言 用户验证用户是否合法登陆. 部分内容在DRF视图的使用及源码流程分析讲解,建议先看讲解视图的这篇文章. 使用流程 认证使用的方法流程如下: 自定义认证类,继承BaseAuthenticat ...

  7. drf-day3——drf整体流程、APIView执行流程及源码分析、Request对象源码分析、序列化器介绍和使用、反序列化的使用、反序列化的校验

    目录 一.drf 整体内容 二.APIView执行流程--源码分析(难,了解) 2.1 基于APIView+JsonResponse编写接口 2.2 基于APIView+Response 写接口 2. ...

  8. HashMap在JDK1.8中并发操作,代码测试以及源码分析

    HashMap在JDK1.8中并发操作不会出现死循环,只会出现缺数据.测试如下: package JDKSource; import java.util.HashMap; import java.ut ...

  9. 时间轮机制在Redisson分布式锁中的实际应用以及时间轮源码分析

    本篇文章主要基于Redisson中实现的分布式锁机制继续进行展开,分析Redisson中的时间轮机制. 在前面分析的Redisson的分布式锁实现中,有一个Watch Dog机制来对锁键进行续约,代码 ...

  10. Flink中TaskManager端执行用户逻辑过程(源码分析)

    TaskManager接收到来自JobManager的jobGraph转换得到的TDD对象,启动了任务,在StreamInputProcessor类的processInput()方法中 通过一个whi ...

随机推荐

  1. Linux shell usage()使用说明

    usage()类似于执行文件-help展示的内容,即告诉使用者有哪些参数选项可供使用. usage()格式 点击查看代码 #!/bin/bash usage() { echo "Usage: ...

  2. VMwareWorkstation-安装虚拟机

    安装vmware 首先就是下载VMware客户端了,Vmware是收费的,过好大多数都有破解版,或者激活码 这里我是用的是VMware16,下载在网上搜一下就有,例如 下载解压后里面有一个后缀为exe ...

  3. 什么是Markdown

    什么是markdown? Markdown是一种轻量级标记语言,它允许人们使用已读一些的纯文本格式编写文档,然后转换成有效的XHTML(或者HTML)文档.这种语言吸收了很多在电子邮件中已有的纯文本标 ...

  4. Linux的文件权限管理

    Linux文件权限管理介绍 一:Ubuntu 简介 1 .什么是Ubuntu Ubuntu是基于Debian开发的一个开源的Linux操作系统,Ubuntu这个名字名称来⾃⾮洲南部某种语言的一个词语, ...

  5. P8112 符文破译

    题目描述 将字符串 \(T\) 拆成若干个子串,使这些子串为字符串 \(S\) 的前缀,要求拆分形成的子串数最小. 思路整理 实际上并不需要倒着枚举,也不需要线段树,更不需要 Z 函数. 如果你做过 ...

  6. java数组使用、Arrays类使用 、排序方法

    数组使用 数组的基本使用: package charpter4; public class ArrayDemo2 { public static void main(String[] args) { ...

  7. flutter issue---->Scaffold.of(context)

    当我们想showSnackBar的时候,需要通过Scaffold.of(context)得到Scaffold.但是如果这个context用错的话,flutter就会抛出错误.下面我们通过代码仔细看一下 ...

  8. 前端ffmpeg实现视频剪切

    利用ffmpeg实现纯前端视频剪切 注意:在新版本Chrome浏览器中由于安全性问题,只能在https或localhost当中才能正常使用 1. 下载ffmpeg npm install @ffmpe ...

  9. Gartner最新报告,分析超大规模边缘解决方案

    当下,酝酿能量的超级边缘. 最近,我们在谈视频化狂飙.谈AIGC颠覆.谈算力动能不足,很少谈及边缘.但"边缘"恰恰与这一切相关,且越发密不可分,它是未来技术发展的极大影响因子. & ...

  10. Java Heap

    堆 堆是一种基于树的数据结构,是一种完全二叉树,堆中的所有的节点都按照特定的顺序排列. 在堆数据结构中,如果任意父节点的值都大于其子节点,则会产生一个大顶堆:反之,如果任意父节点的值都小于其子节点,则 ...