工程化与框架系列(13)--虚拟DOM实现

虚拟DOM实现 🌳

虚拟DOM(Virtual DOM)是现代前端框架的核心技术之一,它通过在内存中维护UI的虚拟表示来提高渲染性能。本文将深入探讨虚拟DOM的实现原理和关键技术。

虚拟DOM概述 🌟

💡 小知识:虚拟DOM是对真实DOM的一种轻量级抽象表示,它以JavaScript对象的形式存在,通过diff算法计算最小更新路径,从而减少对实际DOM的操作。

为什么需要虚拟DOM

在现代前端开发中,虚拟DOM带来以下优势:

  1. 性能优化

    • 批量DOM更新
    • 最小化DOM操作
    • 跨平台渲染
    • 服务端渲染
  2. 开发体验

    • 声明式编程
    • 组件化开发
    • 状态驱动UI
    • 代码可维护性
  3. 跨平台能力

    • 浏览器渲染
    • 原生应用渲染
    • 服务端渲染
    • Canvas/WebGL渲染
  4. 调试能力

    • 状态追踪
    • 组件调试
    • 性能分析
    • 错误边界

核心实现 ⚡

虚拟DOM节点定义

// vnode.ts
export type VNodeType = string | Component;export interface VNode {type: VNodeType;props: Record<string, any>;children: (VNode | string)[];key?: string | number;el?: HTMLElement | Text;
}export interface Component {render: () => VNode;props?: Record<string, any>;setup?: (props: Record<string, any>) => Record<string, any>;
}export function h(type: VNodeType,props: Record<string, any> = {},children: (VNode | string)[] = []
): VNode {return {type,props,children,key: props.key};
}// JSX类型定义
declare global {namespace JSX {interface Element extends VNode {}interface IntrinsicElements {[elemName: string]: any;}}
}// 创建文本节点
export function createTextVNode(text: string): VNode {return {type: 'text',props: {},children: [text]};
}// 创建Fragment
export function Fragment(props: Record<string, any>): VNode {return {type: 'fragment',props,children: props.children || []};
}

DOM渲染实现

// renderer.ts
export class Renderer {private container: HTMLElement;constructor(container: HTMLElement) {this.container = container;}render(vnode: VNode | null) {if (vnode === null) {// 卸载if (this.container.firstChild) {this.container.innerHTML = '';}return;}// 挂载或更新const prevVNode = this.container._vnode;if (!prevVNode) {// 首次挂载this.mount(vnode, this.container);} else {// 更新this.patch(prevVNode, vnode, this.container);}this.container._vnode = vnode;}private mount(vnode: VNode, container: HTMLElement, anchor?: Node | null) {const { type, props, children } = vnode;if (typeof type === 'string') {// 创建元素const el = document.createElement(type);vnode.el = el;// 设置属性this.patchProps(el, {}, props);// 挂载子节点children.forEach(child => {if (typeof child === 'string') {el.appendChild(document.createTextNode(child));} else {this.mount(child, el);}});// 插入到容器container.insertBefore(el, anchor || null);} else if (typeof type === 'function') {// 挂载组件this.mountComponent(vnode, container, anchor);}}private mountComponent(vnode: VNode,container: HTMLElement,anchor?: Node | null) {const component = vnode.type as Component;// 执行setuplet setupResult = {};if (component.setup) {setupResult = component.setup(vnode.props);}// 执行renderconst renderVNode = component.render.call(setupResult);// 挂载渲染结果this.mount(renderVNode, container, anchor);vnode.el = renderVNode.el;}private patch(n1: VNode,n2: VNode,container: HTMLElement,anchor?: Node | null) {if (n1.type !== n2.type) {// 类型不同,直接替换this.unmount(n1);this.mount(n2, container, anchor);return;}if (typeof n2.type === 'string') {// 更新元素const el = (n2.el = n1.el as HTMLElement);// 更新属性this.patchProps(el, n1.props, n2.props);// 更新子节点this.patchChildren(n1, n2, el);} else if (typeof n2.type === 'function') {// 更新组件this.patchComponent(n1, n2, container);}}private patchProps(el: HTMLElement,oldProps: Record<string, any>,newProps: Record<string, any>) {// 移除旧属性for (const key in oldProps) {if (!(key in newProps)) {if (key.startsWith('on')) {const event = key.slice(2).toLowerCase();el.removeEventListener(event, oldProps[key]);} else {el.removeAttribute(key);}}}// 设置新属性for (const key in newProps) {const newValue = newProps[key];const oldValue = oldProps[key];if (newValue !== oldValue) {if (key.startsWith('on')) {// 事件处理const event = key.slice(2).toLowerCase();if (oldValue) {el.removeEventListener(event, oldValue);}el.addEventListener(event, newValue);} else if (key === 'style') {// 样式处理if (typeof newValue === 'string') {el.style.cssText = newValue;} else {for (const styleKey in newValue) {el.style[styleKey] = newValue[styleKey];}}} else if (key === 'class') {// 类名处理if (Array.isArray(newValue)) {el.className = newValue.join(' ');} else {el.className = newValue;}} else {// 其他属性el.setAttribute(key, newValue);}}}}private patchChildren(n1: VNode, n2: VNode, container: HTMLElement) {const oldChildren = n1.children;const newChildren = n2.children;// 处理文本节点if (typeof newChildren[0] === 'string') {if (typeof oldChildren[0] === 'string') {// 文本节点更新if (newChildren[0] !== oldChildren[0]) {container.textContent = newChildren[0];}} else {// 替换为文本节点container.textContent = newChildren[0];}return;}// 处理子节点数组const oldLen = oldChildren.length;const newLen = newChildren.length;const commonLen = Math.min(oldLen, newLen);// 更新公共部分for (let i = 0; i < commonLen; i++) {this.patch(oldChildren[i] as VNode,newChildren[i] as VNode,container);}if (newLen > oldLen) {// 添加新节点for (let i = commonLen; i < newLen; i++) {this.mount(newChildren[i] as VNode, container);}} else if (oldLen > newLen) {// 移除多余节点for (let i = commonLen; i < oldLen; i++) {this.unmount(oldChildren[i] as VNode);}}}private unmount(vnode: VNode) {if (typeof vnode.type === 'string') {vnode.el?.parentNode?.removeChild(vnode.el);} else if (typeof vnode.type === 'function') {// 组件卸载if (vnode.el) {vnode.el.parentNode?.removeChild(vnode.el);}}}
}

Diff算法实现

// diff.ts
interface KeyToIndexMap {[key: string]: number;
}export function patchKeyedChildren(oldChildren: VNode[],newChildren: VNode[],container: HTMLElement
) {let oldStartIdx = 0;let oldEndIdx = oldChildren.length - 1;let newStartIdx = 0;let newEndIdx = newChildren.length - 1;let oldStartVNode = oldChildren[oldStartIdx];let oldEndVNode = oldChildren[oldEndIdx];let newStartVNode = newChildren[newStartIdx];let newEndVNode = newChildren[newEndIdx];const keyToIndexMap: KeyToIndexMap = {};while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {if (!oldStartVNode) {oldStartVNode = oldChildren[++oldStartIdx];} else if (!oldEndVNode) {oldEndVNode = oldChildren[--oldEndIdx];} else if (isSameVNode(oldStartVNode, newStartVNode)) {// 头部节点相同patch(oldStartVNode, newStartVNode, container);oldStartVNode = oldChildren[++oldStartIdx];newStartVNode = newChildren[++newStartIdx];} else if (isSameVNode(oldEndVNode, newEndVNode)) {// 尾部节点相同patch(oldEndVNode, newEndVNode, container);oldEndVNode = oldChildren[--oldEndIdx];newEndVNode = newChildren[--newEndIdx];} else if (isSameVNode(oldStartVNode, newEndVNode)) {// 老头和新尾相同patch(oldStartVNode, newEndVNode, container);container.insertBefore(oldStartVNode.el!,oldEndVNode.el!.nextSibling);oldStartVNode = oldChildren[++oldStartIdx];newEndVNode = newChildren[--newEndIdx];} else if (isSameVNode(oldEndVNode, newStartVNode)) {// 老尾和新头相同patch(oldEndVNode, newStartVNode, container);container.insertBefore(oldEndVNode.el!, oldStartVNode.el!);oldEndVNode = oldChildren[--oldEndIdx];newStartVNode = newChildren[++newStartIdx];} else {// 处理其他情况if (!keyToIndexMap) {// 生成旧节点的key映射for (let i = oldStartIdx; i <= oldEndIdx; i++) {const key = oldChildren[i].key;if (key != null) {keyToIndexMap[key] = i;}}}// 在旧节点中寻找新头节点const idxInOld = keyToIndexMap[newStartVNode.key!];if (idxInOld === undefined) {// 新节点mount(newStartVNode, container, oldStartVNode.el!);} else {// 移动节点const vnodeToMove = oldChildren[idxInOld];patch(vnodeToMove, newStartVNode, container);container.insertBefore(vnodeToMove.el!, oldStartVNode.el!);oldChildren[idxInOld] = undefined as any;}newStartVNode = newChildren[++newStartIdx];}}// 处理剩余节点if (oldStartIdx > oldEndIdx) {// 添加新节点const anchor = newChildren[newEndIdx + 1]? newChildren[newEndIdx + 1].el: null;for (let i = newStartIdx; i <= newEndIdx; i++) {mount(newChildren[i], container, anchor);}} else if (newStartIdx > newEndIdx) {// 移除多余节点for (let i = oldStartIdx; i <= oldEndIdx; i++) {if (oldChildren[i]) {unmount(oldChildren[i]);}}}
}function isSameVNode(n1: VNode, n2: VNode): boolean {return n1.type === n2.type && n1.key === n2.key;
}

组件系统实现 🏗️

组件定义

// component.ts
export interface ComponentOptions {name?: string;props?: Record<string, PropOptions>;setup?: (props: Record<string, any>,context: SetupContext) => Record<string, any>;render?: () => VNode;
}interface PropOptions {type: any;required?: boolean;default?: any;validator?: (value: any) => boolean;
}interface SetupContext {attrs: Record<string, any>;slots: Record<string, (...args: any[]) => VNode[]>;emit: (event: string, ...args: any[]) => void;
}export function defineComponent(options: ComponentOptions) {return {name: options.name,props: options.props,setup: options.setup,render: options.render,// 组件实例创建create(props: Record<string, any>) {// 创建组件实例const instance = {props: shallowReactive(props),attrs: {},slots: {},emit: (event: string, ...args: any[]) => {const handler = props[`on${capitalize(event)}`];if (handler) {handler(...args);}}};// 执行setupif (options.setup) {const setupContext = {attrs: instance.attrs,slots: instance.slots,emit: instance.emit};const setupResult = options.setup(instance.props,setupContext);if (typeof setupResult === 'function') {// setup返回渲染函数instance.render = setupResult;} else if (typeof setupResult === 'object') {// setup返回状态对象instance.setupState = proxyRefs(setupResult);}}// 渲染函数instance.render = options.render || instance.render;return instance;}};
}// 工具函数
function capitalize(str: string): string {return str.charAt(0).toUpperCase() + str.slice(1);
}

生命周期实现

// lifecycle.ts
export const enum LifecycleHooks {BEFORE_CREATE = 'beforeCreate',CREATED = 'created',BEFORE_MOUNT = 'beforeMount',MOUNTED = 'mounted',BEFORE_UPDATE = 'beforeUpdate',UPDATED = 'updated',BEFORE_UNMOUNT = 'beforeUnmount',UNMOUNTED = 'unmounted'
}export function injectHook(type: LifecycleHooks,hook: Function,target: any
): Function | undefined {if (target) {const hooks = target[type] || (target[type] = []);const wrappedHook = (...args: any[]) => {hook.call(target, ...args);};hooks.push(wrappedHook);return wrappedHook;}
}export const createHook = (lifecycle: LifecycleHooks) => {return (hook: Function, target: any = currentInstance) =>injectHook(lifecycle, hook, target);
};export const onBeforeMount = createHook(LifecycleHooks.BEFORE_MOUNT);
export const onMounted = createHook(LifecycleHooks.MOUNTED);
export const onBeforeUpdate = createHook(LifecycleHooks.BEFORE_UPDATE);
export const onUpdated = createHook(LifecycleHooks.UPDATED);
export const onBeforeUnmount = createHook(LifecycleHooks.BEFORE_UNMOUNT);
export const onUnmounted = createHook(LifecycleHooks.UNMOUNTED);

性能优化 ⚡

静态节点优化

// optimize.ts
interface StaticNodeAnalysis {isStatic: boolean;staticRoot: boolean;
}export function optimizeNode(node: VNode): StaticNodeAnalysis {if (typeof node.type === 'string') {// 分析静态节点const analysis: StaticNodeAnalysis = {isStatic: true,staticRoot: false};// 检查属性for (const key in node.props) {if (key === 'v-if' ||key === 'v-for' ||key === 'v-model' ||key.startsWith(':') ||key.startsWith('@')) {analysis.isStatic = false;break;}}// 检查子节点if (analysis.isStatic && node.children.length > 0) {let allChildrenStatic = true;let staticChildCount = 0;for (const child of node.children) {if (typeof child === 'object') {const childAnalysis = optimizeNode(child);if (!childAnalysis.isStatic) {allChildrenStatic = false;break;}if (childAnalysis.staticRoot) {staticChildCount++;}}}analysis.staticRoot =allChildrenStatic && staticChildCount > 0;}return analysis;}return {isStatic: false,staticRoot: false};
}// 标记静态根节点
export function markStaticRoots(node: VNode, analysis: StaticNodeAnalysis) {if (analysis.staticRoot) {node.staticRoot = true;// 缓存静态子树node.staticChildren = [...node.children];}// 递归处理子节点for (const child of node.children) {if (typeof child === 'object') {const childAnalysis = optimizeNode(child);markStaticRoots(child, childAnalysis);}}
}

更新优化

// update-optimization.ts
export class UpdateOptimizer {private static readonly BATCH_SIZE = 1000;private updates: Set<VNode> = new Set();private updating = false;queueUpdate(vnode: VNode) {this.updates.add(vnode);if (!this.updating) {this.updating = true;requestAnimationFrame(() => this.processUpdates());}}private processUpdates() {const updates = Array.from(this.updates);this.updates.clear();this.updating = false;// 批量处理更新for (let i = 0; i < updates.length; i += this.BATCH_SIZE) {const batch = updates.slice(i, i + this.BATCH_SIZE);this.processBatch(batch);}}private processBatch(vnodes: VNode[]) {// 按照组件层级排序vnodes.sort((a, b) => getDepth(a) - getDepth(b));// 合并同层级更新const updateMap = new Map<number, VNode[]>();for (const vnode of vnodes) {const depth = getDepth(vnode);if (!updateMap.has(depth)) {updateMap.set(depth, []);}updateMap.get(depth)!.push(vnode);}// 按层级处理更新for (const [depth, nodes] of updateMap) {this.processDepthUpdates(nodes);}}private processDepthUpdates(vnodes: VNode[]) {// 处理同一层级的更新for (const vnode of vnodes) {if (vnode.staticRoot) {// 跳过静态根节点continue;}// 更新节点patch(vnode, vnode, vnode.el!.parentNode);}}
}function getDepth(vnode: VNode): number {let depth = 0;let current = vnode;while (current.parent) {depth++;current = current.parent;}return depth;
}

最佳实践建议 ⭐

性能优化建议

  1. 节点优化

    • 使用key标识
    • 提取静态节点
    • 避免深层嵌套
    • 合理使用v-show
  2. 更新优化

    • 批量更新
    • 异步更新
    • 合并操作
    • 缓存结果
  3. 渲染优化

    • 懒加载组件
    • 虚拟滚动
    • 时间切片
    • 优先级调度

开发建议

  1. 组件设计
// 好的实践
const GoodComponent = defineComponent({name: 'GoodComponent',props: {items: {type: Array,required: true}},setup(props) {// 提取复杂逻辑const state = reactive({selectedIndex: -1});// 计算属性const filteredItems = computed(() =>props.items.filter(item => item.visible));return {state,filteredItems};}
});// 避免这样做
const BadComponent = defineComponent({render() {// 渲染函数中包含复杂逻辑const items = this.items.filter(item => {return item.visible && this.complexCheck(item);});return h('div', {}, items.map(item =>h('div', { key: item.id }, item.name)));}
});
  1. 更新处理
// 好的实践
function handleUpdates() {// 批量更新nextTick(() => {state.count++;state.total = calculateTotal();});
}// 避免频繁更新
function badUpdate() {state.count++;state.total = calculateTotal();// 直接触发DOM更新
}

结语 📝

虚拟DOM是现代前端框架的重要基石,通过本文,我们学习了:

  1. 虚拟DOM的核心概念
  2. DOM diff算法的实现
  3. 组件系统的设计
  4. 性能优化的策略
  5. 开发中的最佳实践

💡 学习建议:

  1. 深入理解虚拟DOM原理
  2. 掌握diff算法的优化
  3. 注重性能优化实践
  4. 遵循最佳实践指南
  5. 持续学习新的优化方案

如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇

终身学习,共同成长。

咱们下一期见

💻

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/71092.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

设计模式--spring中用到的设计模式

一、单例模式&#xff08;Singleton Pattern&#xff09; 定义&#xff1a;确保一个类只有一个实例&#xff0c;并提供全局访问点 Spring中的应用&#xff1a;Spring默认将Bean配置为单例模式 案例&#xff1a; Component public class MySingletonBean {// Spring 默认将其…

深入浅出:Spring AI 集成 DeepSeek 构建智能应用

Spring AI 作为 Java 生态中备受瞩目的 AI 应用开发框架&#xff0c;凭借其简洁的 API 设计和强大的功能&#xff0c;为开发者提供了构建智能应用的强大工具。与此同时&#xff0c;DeepSeek 作为领先的 AI 模型服务提供商&#xff0c;在自然语言处理、计算机视觉等领域展现了卓…

CSS浮动详解

1. 浮动的简介 浮动是用来实现文字环绕图片效果的 2.元素浮动后会有哪些影响 对兄弟元素的影响&#xff1a; 后面的兄弟元素&#xff0c;会占据浮动元素之前的位置&#xff0c;在浮动元素的下面&#xff1b;对前面的兄弟 无影响。 对父元素的影响&#xff1a; 不能撑起父元…

python数据类型等基础语法

目录 字面量 注释 变量 查数据类型 类型转换 算数运算符 字符串定义的三种方式 字符串占位 数据输入 字面量 被写在代码中固定的值 六种数据类型: 1 字符串 String 如"egg" 2 数字 Number: 整数int 浮点数float 复数complex :如43j 布尔…

Android 图片压缩详解

在 Android 开发中,图片压缩是一个重要的优化手段,旨在提升用户体验、减少网络传输量以及降低存储空间占用。以下是几种主流的图片压缩方法,结合原理、使用场景和优缺点进行详细解析。 效果演示 直接先给大家对比几种图片压缩的效果 质量压缩 质量压缩:根据传递进去的质…

Flutter状态管理框架GetX最新版详解与实践指南

一、GetX框架概述 GetX是Flutter生态中轻量级、高性能的全能开发框架&#xff0c;集成了状态管理、路由导航、依赖注入等核心功能&#xff0c;同时提供国际化、主题切换等实用工具。其优势在于代码简洁性&#xff08;减少模板代码约70%&#xff09;和高性能&#xff08;基于观…

【linux】详谈 环境变量

目录 一、基本概念 二、常见的环境变量 取消环境变量 三、获取环境变量 通过代码获取环境变量 环境变量的特性 1. getenv函数:获取指定的环境变量 2. environ获取环境变量 四、本地变量 五、定义环境变量的方法 临时定义&#xff08;仅对当前会话有效&#xff09; 永…

LangChain教程 - RAG - PDF问答

系列文章索引 LangChain教程 - 系列文章 在现代自然语言处理&#xff08;NLP&#xff09;中&#xff0c;基于文档内容的问答系统变得愈发重要&#xff0c;尤其是当我们需要从大量文档中提取信息时。通过结合文档检索和生成模型&#xff08;如RAG&#xff0c;Retrieval-Augment…

大白话前端性能优化方法的分类与具体实现

大白话前端性能优化方法的分类与具体实现 一、资源加载优化 1. 压缩与合并文件 大白话解释&#xff1a; 咱们的网页代码里&#xff0c;就像一个房间堆满了东西&#xff0c;有很多没用的“杂物”&#xff0c;比如代码里的空格、注释啥的。压缩文件就是把这些“杂物”清理掉&a…

MySQL并发知识(面试高频)

mysql并发事务解决 不同隔离级别下&#xff0c;mysql解决并发事务的方式不同。主要由锁机制和MVCC(多版本并发控制)机制来解决并发事务问题。 1. mysql中的锁有哪些&#xff1f; 表级锁&#xff1a; 场景&#xff1a;表级锁适用于需要对整个表进行操作的情况&#xff0c;例如…

【Kubernets】K8S内部nginx访问Service资源原理说明

文章目录 原理概述**一、核心概念****二、Nginx 访问 Service 的流程****1. Service 的作用****2. Endpoint 的作用****3. Nginx Pod 发起请求****(1) DNS 解析****(2) 流量到达 kube-proxy****(3) 后端 Pod 处理请求** **三、不同代理模式的工作原理****1. iptables 模式****2…

HTML:自闭合标签简单介绍

1. 什么是自结束标签&#xff1f; 定义&#xff1a;自结束标签&#xff08;Self-closing Tag&#xff09;是指 不需要单独结束标签 的 HTML 标签&#xff0c;它们通过自身的语法结构闭合。语法形式&#xff1a; 在 HTML5 中&#xff1a;直接写作 <tag>&#xff0c;例如 …

《几何原本》公理

《几何原本》公理 等于同量的量彼此相等 即若 a b , b c ab,bc ab,bc 则 a c ac ac 等量加等量&#xff0c;其和仍相等 即若 a b ab ab 则 a c b c acbc acbc 等量减等量&#xff0c;其差仍相等 即若 a b ab ab 则 a − c b − c a-cb-c a−cb−c 彼此能够&a…

学习路程十一 langchain核心组件 Memory

前序 在最开始我们就通过实验知道LLM 本身是没有记忆的&#xff0c;每一次LLM的API调用都是一个全新的会话。但在某些应用程序中&#xff0c;如&#xff1a;聊天机器人&#xff0c;让LLM记住以前的历史交互是非常重要&#xff0c;无论是在短期的还是长期的。langchain中的“Me…

Spring-AI搭建企业专属知识库 一

环境介绍&#xff1a;Spring3.3.2 JDK 21 POM文件 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation&…

C语言多级指针详解 - 通过实例理解一级、二级、三级指针

C语言多级指针详解 - 通过实例理解一级、二级、三级指针 文章目录 C语言多级指针详解 - 通过实例理解一级、二级、三级指针引言一、示例代码二、指针基础回顾&#xff08;先备知识&#xff09;1.生活中的类比2.指针变量定义3.关键操作符4.解引用本质 三、多级指针的本质1.层级关…

Difyにおけるデータベースマイグレーション手順

Difyにおけるデータベースマイグレーション手順 はじめに主要マイグレーションコマンドAlembic直接コマンドFlask-Migrate経由コマンド 標準マイグレーション作業フローデプロイ時の対応注意事項 はじめに Difyプロジェクトでのデータベースマイグレーションには、Alembicコマ…

React + TypeScript 实现 SQL 脚本生成全栈实践

React TypeScript 实现数据模型驱动 SQL 脚本生成全栈实践 引言&#xff1a;数据模型与 SQL 的桥梁革命 在现代化全栈开发中&#xff0c;数据模型与数据库的精准映射已成为提升开发效率的关键。传统手动编写 SQL 脚本的方式存在模式漂移风险高&#xff08;Schema Drift&#…

Python 高精度计算利器:decimal 模块详解

Python 高精度计算利器&#xff1a;decimal 模块详解 在 Python 编程中&#xff0c;处理浮点数时&#xff0c;标准的 float 类型往往会因二进制表示的特性而产生精度问题。decimal 模块应运而生&#xff0c;它提供了十进制浮点运算功能&#xff0c;能让开发者在需要高精度计算…

freertos 学习5--链路状态设置

以下三个函数都是针对网卡netif的操作。1 netif_set_up函数(netif_set_down) 特点 直接操作网络接口&#xff0c;不通过 netifapi 机制。 适用于单线程环境&#xff0c;或者在多线程环境中需要额外加锁。1.1 netif_set_up 对比windows下面&#xff0c;相当于是在资源管理器中…