平时使用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. pugixml XML格式处理库的介绍和使用(面向业务编程-格式处理)

    pugixml XML格式处理库的介绍和使用(面向业务编程-格式处理) 介绍 pugixml是一个轻量级的C++ XML处理库.它的特点: 类似dom的界面,具有丰富的遍历/修改功能 非常快速的非验证 ...

  2. 什么是RPA?RPA能干什么?

    一.什么是RPA什么是RPA? RPA的全称为机器人流程自动化(Robotic Process Automation),即:"机器人流程自动化",是一种智能化的企业流程管理系统.R ...

  3. 【读书笔记】排列研究-置换角度(分解为Products Of Cycles) 含GroupExploer使用

    upd 2020-08-06 23:11完成了最初稿 目录 定义 开胃菜 entrée 群论角度 应用:几何变换 当然要从第一类斯特林数的角度来考虑一下 一个排列的type定义 排旗公式 应用-共轭排 ...

  4. 使用 DeepSpeed 和 Hugging Face 🤗 Transformer 微调 FLAN-T5 XL/XXL

    Scaling Instruction-Finetuned Language Models 论文发布了 FLAN-T5 模型,它是 T5 模型的增强版.FLAN-T5 由很多各种各样的任务微调而得,因 ...

  5. 基于docker和cri-dockerd部署k8sv1.26.3

    cri-dockerd是什么? 在 Kubernetes v1.24 及更早版本中,我们使用docker作为容器引擎在k8s上使用时,依赖一个dockershim的内置k8s组件:k8s v1.24发 ...

  6. Java 8 中需要知道的4个函数式接口-Function、Consumer、Supplier、Predicate

    前言 Java 8 中提供了许多函数式接口,包括Function.Consumer.Supplier.Predicate 等等.这 4 个接口就是本篇将要分享的内容,它们都位于 java.util.f ...

  7. [Linux]常用命令之【nl/sed/awk/wc/xargs/perl】

    nl nl : 在linux系统中用来计算文件中行号. nl 可以将输出的文件内容自动的加上行号!其默认的结果与 cat -n 有点不太一样, nl 可以将行号做比较多的显示设计,包括位数与是否自动补 ...

  8. Docker中Nginx搭建以及配置

    docker nginx搭建 1 docker pull nginx docker pull nginx 2 启动nginx docker run --name nginx -p 80:80 -d n ...

  9. GIL和池的概念

    1.GIL概念 1. 什么是GIL(为Cpython解释器) GIL本身就是一把互斥锁. 原理都一样. 都是让并发的线程同一时间只能执行一个 所以有了GIL的存在. 同一进程下的多个线程同一时刻只能有 ...

  10. 论文解读(PAWS)《Semi-Supervised Learning of Visual Features by Non-Parametrically Predicting View Assignments with Support Samples》

    论文信息 论文标题:Semi-Supervised Learning of Visual Features by Non-Parametrically Predicting View Assignme ...