block底层实现(一)

首先先写一个最简单的block,代码如下

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {

    void(^blk)() = ^{printf("test1\n");};
    
    blk();

}


利用clang(LLVM编译器)可以转换为我们可读源代码,通过-rewrite-objc 选项就能将代码转换为C++源码,说是C++,其实也只是用到了里面的结构体,转换后源码有接近10W行,下面只截取相关部份,代码如下

struct __block_impl {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};

//我们自己写的代码转换后如下
struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
printf("test1\n");}

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
int main(int argc, const char * argv[]) {

    void(*blk)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));

    ((void (*)(__block_impl *))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk);

}


首先定义了一结构体
__main_block_impl_0
从主函数main中可以看到blk是一个函数指针,指向了一个__main_block_impl_0的结构体地址,其中的__block_impl又是一个结构体,结构体中有四个字段,第一个字段void *isa,说明其可以成员一个OC对象,第四个字段FuncPtr,从名字就可以猜出,它是一个函数指针,

__main_block_impl_0 这个结构体命名意思就是main函数中第0个block的implementation,如果在别的函数中定义并实现block,如test()函数,其对应的结构体就是__test_block_impl_0...

__main_block_impl_0结构体中写了一个带参的构造函数,用来初始化成员变量,

第一个参数传入的是block实际执行代码所在的函数的地址,当block真正被执行时,实际上就是调了这个函数,

第二个参数传入的block的描述结构体,这个结构体在声明结束时就创建一个唯一的desc,这个desc包含了block的大小,以及复制各析构block时需要额外调用的函数(copy,dispose)//注,这个在使用__block变量时,对block进行copy操作,并会生成这两个字段,

由此一个__main_block_impl_o结构体便生成了,主函数main,最后调用,其转换过程如下,将blk函数指针强转为__block_impl指针,然后取其执行函数指针,然后将此指针类型强转为一个无返回值,并接受一个__block_impl*参数的函数指针,并调用这个函数指针,传入强转为__block_impl*类型的blk,至此即完成了block的调用


由于转换较为复杂,下面我间接写一个转换中间代码


typedef void(*BLOCK)(void)//无参无返回值的函数指针
typedef void(*BLOCKIMP)(struct  *__block_impl) //无返回值,带一个结构体指针
void *fp = (void *)__main_block_func_0 //取block执行函数地址
__main_block_desc_0 *desc = &__main_block_desc_0_DATA //取block描述结构体
__main_block_impl_0 tmp = __main_block_impl_0( fp,  desc); //构造一个__main_block_impl_0结构体
BLOCK blk = (BLOCK)&tmp; //取__main_block_impl_0结构体的地址,然后将其强转为一个无参无返回值的函数指针
__block_impl *blktmp = (__block_impl*)blk;//将blk强转为__block_impl类型,目的是取其执行函数地址
BLOCKIMP blkimp = (BLOCKIMP) blktmp->FuncPtr;//取其执行函数地址,然后强转为一个无返回值,带一个结构体指针
blkimp(blktmp)//函数调用


至此这个调用就完成了











<think>好的,用户现在想了解Vue的底层实现原理,特别是源码分析、响应式机制和虚拟DOM。首先,我需要整理下之前提供的引用内容,看看有哪些相关信息可以利用。用户之前已经询问过前端跨域的问题,现在转向Vue的内部机制,可能需要从基础开始解释,同时结合源码结构。 首先,用户提到的三个引用分别涉及Vue2和Vue3的源码分析,特别是响应式系统和编译过程。引用1提到了Vue2的compiler步骤,包括AST分析和优化静态节点。引用2讨论了Vue3的响应式模块,如reactive、effect等。引用3则涉及Vue2的响应式原理,比如render函数如何访问data属性。 用户的需求是了解Vue的底层实现,可能需要分模块讲解,比如响应式、虚拟DOM、模板编译等。同时,用户可能希望知道Vue2和Vue3之间的区别,尤其是响应式系统从Object.defineProperty到Proxy的变化。 需要先确定回答的结构,可能分成几个主要部分:响应式机制、虚拟DOM、模板编译、源码结构。每个部分需要结合引用中的例子,比如Vue2的Observer和Dep,Vue3的Proxy和effect。同时,比较Vue2和Vue3的不同之处,帮助用户理解演进的原因。 在响应式机制部分,需要详细说明依赖收集和触发更新的过程。Vue2使用getter/setter,而Vue3使用Proxy,这能更好地处理数组和新增属性。虚拟DOM部分要解释为什么需要虚拟DOM,以及diff算法的优化策略,比如同级比较、key的作用等。 模板编译部分需要解释如何将模板转化为AST,再生成render函数,以及优化静态节点的过程。可能还要提到Vue3的编译时优化,比如块(block)的概念,减少运行时开销。 源码结构方面,根据引用1中的Vue2模块划分,如core、observer、vdom等,可以简要介绍各个模块的作用。Vue3的模块化设计可能更清晰,比如reactivity模块独立,方便其他项目使用。 另外,用户可能对实际应用中的优化策略感兴趣,比如为什么Vue3的响应式更快,或者虚拟DOM如何提升性能。需要结合引用中的例子,比如Vue2的静态节点优化,Vue3的Proxy优势。 还要注意用户可能存在的疑问点,比如为什么Vue3改用Proxy,虚拟DOM和直接操作DOM的优劣,或者响应式系统的局限。在回答中适当加入这些对比和解释,能帮助用户更深入理解。 最后,生成的相关问题需要覆盖用户可能进步探索的方向,比如Vue3的Composition API优势,响应式系统的实现细节,或者虚拟DOM的diff算法具体策略。这样用户可以按需继续学习。</think>--- ### Vue 底层实现原理深度解析(整合Vue2/Vue3源码分析) --- #### 、响应式机制 ##### 1. Vue2 实现(Object.defineProperty) **核心流程**: 1. **数据劫持**:通过 `Object.defineProperty` 递归劫持对象属性 ```javascript // Observer 类核心逻辑(简化) class Observer { constructor(value) { this.walk(value); } walk(obj) { Object.keys(obj).forEach(key => { defineReactive(obj, key, obj[key]); }); } } function defineReactive(obj, key, val) { const dep = new Dep(); // 依赖管理器 Object.defineProperty(obj, key, { get() { if (Dep.target) { dep.depend(); // 收集当前渲染Watcher[^3] } return val; }, set(newVal) { if (newVal === val) return; val = newVal; dep.notify(); // 触发更新 } }); } ``` 2. **依赖管理**: - **Dep**:每个属性对应个Dep实例,管理所有订阅者(Watcher) - **Watcher**:组件渲染时创建,存储更新函数(如 `render` 函数) ##### 2. Vue3 优化(Proxy) **重大改进**: - 支持**数组索引修改**和**对象属性新增/删除** - **惰性代理**:仅在访问时递归代理子对象 ```javascript // Vue3 reactive 实现(简化) function reactive(target) { return new Proxy(target, { get(target, key, receiver) { track(target, key); // 依赖收集 return Reflect.get(target, key, receiver); }, set(target, key, value, receiver) { Reflect.set(target, key, value, receiver); trigger(target, key); // 触发更新 } }); } // 依赖收集与触发(effect 实现) let activeEffect; function effect(fn) { activeEffect = fn; fn(); // 执行时触发getter } function track(target, key) { if (activeEffect) { // 建立 target.key -> effect 映射关系 } } ``` ##### 3. 核心差异对比 | 特性 | Vue2 | Vue3 | |--------------------|--------------------------|--------------------| | 响应式方案 | Object.defineProperty | Proxy | | 数组监听 | 需重写数组方法 | 原生支持 | | 新增属性 | 需 `Vue.set` | 直接响应 | | 性能优化 | 全量递归劫持 | 按需惰性代理 | --- #### 二、虚拟DOM与Diff算法 ##### 1. 设计动机 - **跨平台**:抽象渲染层,可对接不同平台(Web/Weex/Canvas) - **高效更新**:通过对比新旧vnode,最小化DOM操作(时间复杂度$O(n)$) ##### 2. 核心流程 ```mermaid graph TD A[Template] --> B[AST] B --> C[Render Function] C --> D[生成VNode] D -->|首次渲染| E[创建真实DOM] D -->|更新时| F[Diff算法对比新旧VNode] F --> G[DOM Patch] ``` ##### 3. Diff算法优化 - **同级比较**:不跨层级移动节点 - **key标识**:通过唯key复用相同类型节点 - **双端指针**:新旧子节点首尾同时比较(Vue3进步优化为快速路径判断) --- #### 三、模板编译原理 ##### 1. 编译流程(Vue2) 1. **词法分析**:将模板字符串转换为Token流 2. **语法分析**:构建AST(抽象语法树) 3. **代码生成**:将AST转换为render函数 ```javascript // AST节点示例(简化) { type: 1, tag: 'div', attrsList: [{name: 'id', value: 'app'}], children: [ {type: 2, text: '{{message}}', expression: '_s(message)'} ] } // 生成的render函数 function render() { return _c('div', {attrs:{"id":"app"}}, [_v(_s(message))]) } ``` ##### 2. Vue3优化 - **Block Tree**:标记动态节点,跳过静态内容对比 - **Patch Flags**:二进制标记节点更新类型(如 `TEXT`/`CLASS`) --- #### 四、源码架构解析 ##### 1. Vue2核心模块 ```text src/ ├── compiler/ # 模板编译(分词→AST→代码生成) ├── core/ # 核心 │ ├── observer/ # 响应式系统 │ ├── vdom/ # 虚拟DOM实现 │ └── instance/ # 组件实例管理 └── platforms/ # 平台相关代码 ``` ##### 2. Vue3模块化设计 ```text packages/ ├── compiler-core/ # 通用编译逻辑 ├── reactivity/ # 独立响应式系统(可单独使用) ├── runtime-core/ # 跨平台运行时 └── vue/ # 完整构建版本 ``` --- ### 相关问题 1. Vue3的静态提升(Hoist Static)如何提升性能? 2. 虚拟DOM定比直接操作DOM快吗?什么场景下可能更慢? 3. Vue2的数组响应式如何处理 `arr[0]=1` 这种赋值? 4. Composition API 与 Options API 在源码实现上有何本质区别? 5. Vue3的 `effectScope` 解决了哪些开发痛点?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值