选择前端框架重要依据是什么?

状态更改检测,也就是检测应用程序对状态值的改变,这样才会相应地更新 UI。

(#MVC模式中模型Model的改变会更新View界面UI,这点类似后端的ORM,对象状态更改通过ORM框架自动变更相应数据表值)

变更检测是前端框架的基本特征

一个框架对这个问题的解决方式还决定了其他一切:开发人员体验、用户体验、API 表面积、社区满意度和参与度等。

事实证明,从这个角度检查各种框架将为您提供所需的所有信息,以便为您和您的用户确定最佳选择。因此,让我们深入了解每个框架如何处理变更检测。

主要框架比较

我们将研究每个主要参与者以及他们如何处理变更检测,但同样的批判眼光也适用于您可能遇到的任何前端 JavaScript 框架。

ReactJS

React 中的更改检测是通过JS:

开发人员只需通过 API 直接调用 React 的运行时就可更新状态;由于 React 被通知了要进行状态更改,因此它也要知道它需要重新渲染组件。

React长时间发展依赖,编写组件的默认样式已经发生了各种演变变化,但核心原则保持不变。

下面是一个实现按钮计数器的示例组件,以 hooks 风格编写:


export  default function App() {
    const  [count, setCount\] = useState(0);
    return (
        <div>
            <button onClick={() => setCount(count - 1)}>decrement</button>
            <span>{count}</span>
            <button onClick={() => setCount(count + 1)}>increment</button>
            <button onClick={() => setTimeout(() => setCount(count + 1), 1000)}>increment later</button>
        </div>
    );
}

这里的关键部分是setCount函数,这个函数返回给我们的是React的钩子函数useState。

当调用setCount函数时,React 可以使用其内部虚拟 DOM 比较算法来确定要重新渲染页面的哪些部分。

(请注意,这意味着 React 运行时必须包含在用户下载的应用程序包中。)

React 的变更检测范例很简单:应用程序状态在框架内维护(通过向开发人员公开用于更新它的 API),以便 React 知道何时重新渲染。

Angular

当你搭建一个新的 Angular 应用程序时,变更检测似乎会自动发生:

@Component({
    selector: 'counter',
    template: \`
        <div>
            <button (click)="count = count - 1"\>decrement</button>
            <span>{{ count }}</span>
            <button (click)="count = count + 1"\>increment</button>
            <button (click)="incrementLater()"\>increment later</button>
        </div>
    \`
})
export **class** Counter {
    count = 0;

    incrementLater() {
        setTimeout(() => {
            **this**.count++;
        }, 1000);
    }
} 

这里Angular 使用 NgZone 来观察用户操作,并在每个事件中检查整个组件树。

对于任何合理大小的应用程序,这都会导致性能问题,因为快速检查整个树的成本太高。

因此,Angular 允许开发人员选择不同的变更检测策略,从而为这种行为提供了一个逃生门:OnPush

OnPush 意味着开发者有责任在状态发生变化时通知 Angular,以便 Angular 重新渲染组件。除了默认的天真策略,OnPush 是 Angular 提供的唯一一种变化检测策略。启用 OnPush 后,如果新状态被异步更新,我们必须手动告诉 Angular 的变化检测器检查新状态:

@Component({
    selector: 'counter',
    template: \`
        <div>
            <button (click)="count = count - 1"\>decrement</button>
            <span>{{ count }}</span>
            <button (click)="count = count + 1"\>increment</button>
            <button (click)="incrementLater()"\>increment later</button>
        </div>
    \`,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export **class** Counter {
    constructor(**private** readonly cdr: ChangeDetectorRef) {}

    count = 0;

    incrementLater() {
        setTimeout(() => {
            **this**.count++;
            **this**.cdr.markForCheck();
        }, 1000);
    }
} 

对于任何复杂程度的应用来说,这种方法很快就会变得站不住脚。

为了解决这个问题,我们引入了其他解决方案。Angular 文档建议的主要解决方案是将 RxJS 观察对象与 AsyncPipe 结合使用:

enum Action {
    INCREMENT,
    DECREMENT,
    INCREMENT\_LATER
}

@Component({
    selector: 'counter',
    template: \`
        <div>
            <button (click)="update.next(Action.DECREMENT)"\>decrement</button>
            <span>{{ count | async }}</span>
            <button (click)="update.next(Action.INCREMENT)"\>increment</button>
            <button (click)="update.next(Action.INCREMENT\_LATER)"\>increment later</button>
        </div>
    \`,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export **class** Counter {
    readonly update = **new** Subject<Action>();

    readonly count = **this**.update.pipe(
        switchScan((prev, action) => {
            **switch** (action) {
                **case** Action.INCREMENT:
                    **return** of(prev + 1);
                **case** Action.DECREMENT:
                    **return** of(prev - 1);
                **case** Action.INCREMENT\_LATER:
                    **return** of(prev + 1).pipe(delay(1000));
            }
        }, 0),
        startWith(0)
    );

    readonly Action = Action;
} 

在其内部,AsyncPipe 负责订阅观察对象,在观察对象发出新值时通知变化检测器,并在组件销毁时取消订阅。

可观察对象是对随时间发生的状态变化进行建模的一种强大方法,但也有一些严重的缺点:

  • 它们很难调试。
  • 学习曲线非常陡峭。
  • 它们非常适合对数值流(如鼠标移动)进行建模,但对于更常见的用例(简单的状态变化,如复选框的开/关状态)来说,它们就显得多余了。

为了克服默认变更检测模式的缺点,Angular 团队正在开发一种名为信号(Signals)的新方法。

从概念上讲,信号类似于 Svelte 存储(我们稍后会介绍),从根本上讲,它们解决变更检测问题的方式与 React 相同;框架正在控制应用程序的状态,以便轻松监控变更,并尽可能高效地重新呈现。

这是一个巨大的范式转变,使 Angular 应用程序与其他框架更加相似。

Angular 的变更检测是一场灾难。开发人员有两个次优选择:

  1. 缓慢而幼稚的默认实现,或者
  2. 手动管理更改检测的复杂性。

信号将使情况变得更好,尽管已经晚了近十年。

VueJS

Vue 的变更检测方法与 React 和 Angular 略有不同。

您不需要像React那样调用框架函数来更改状态

或像Angular那样更改状态然后通知框架它已更改

而是使用框架专门检测的状态对象来拦截和检测更改。

令人困惑的是,Vue 有两种不同的 API,它们以不同的方式封装了相同的底层变化检测引擎。

在 "Options  API "下,你可以定义一个包含状态的对象,Vue 会将该对象的代理版本作为this对象的成员分配给组件的函数使用:

<template>
    <div>
        <button @click="decrement"\>decrement</button>
        <span>{{ count }}</span>
        <button @click="increment"\>increment</button>
        <button @click="incrementLater"\>increment later</button>
    </div>
</template>

<script>
    export **default** {
        data() {
            **return** {
                count: 0
            };
        },
        methods: {
            decrement() {
                **this**.count--;
            },
            increment() {
                **this**.count++;
            },
            incrementLater() {
                setTimeout(() => {
                    **this**.count++;
                }, 1000);
            }
        }
    };
</script> 

另外,"Composition API "与 React 的钩子有些类似:调用一个框架函数来检索 Vue 可以监控变化的状态对象:

<script setup>
    **import** { ref } from 'vue';

    **const** count = ref(0);

    function increment() {
        count.value++;
    }

    function decrement() {
        count.value--;
    }

    function incrementLater() {
        setTimeout(() => {
            count.value++;
        }, 1000);
    }
</script>

<template>
    <div>
        <button @click="decrement"\>decrement</button>
        <span>{{ count }}</span>
        <button @click="increment"\>increment</button>
        <button @click="incrementLater"\>increment later</button>
    </div>
</template> 

从概念上讲,从 ref() 返回的对象有一个 getter 和一个 setter 值,这样 Vue 就能跟踪对象的变化。

Vue 利用 JavaScript 语言的特性,允许开发人员使用有状态变量,而无需考虑变化检测。

Svelte

从表面上看,Svelte 版本的计数器组件与其他框架非常相似:

<script>
    let count = 0;
    function decrement() {
        count--;
    }
    function increment() {
        count++;
    }
    function incrementLater() {
        setTimeout(() => {
            count++;
        }, 1000);
    }
</script>

<div>
    <button on:click="{decrement}"\>decrement</button>
    <span>{count}</span>
    <button on:click="{increment}"\>increment</button>
    <button on:click="{incrementLater}"\>increment later</button>
</div> 

但相比之下,Svelte 的变化检测方法就显得非常新颖了。

在编译时,Svelte 会分析组件代码的 AST(抽象语法树),并在编译输出中注入一些代码,以便在必要时对 DOM 进行手术式更新。

例如,编译后的 decrement() 函数就是这样的:

function decrement() {
    $$invalidate(0, count--, count);
}

其中 $$invalidate 是对 Svelte 内部的调用,用于指示编译后的组件更新 DOM。

这种编译时方法意味着 Svelte 应用程序不需要将大型运行时与应用程序本身捆绑在一起。

Svelte 取得了罕见的双赢平衡:开发人员根本不必考虑变更检测,并且可以直观地与状态变量交互;然而,最终用户的体验通过更好的性能得到了改善,因为一个最低限度的应用程序(内置更改检测)被发送到浏览器。

总结

这些只是从开发人员的角度举例说明。每种方法都会对最终用户的应用程序性能产生影响。

React、Vue 和 Angular 都会向用户的浏览器发送运行时,需要对运行时进行解析和执行。

Svelte 选择采用编译时框架,因此在大多数情况下都不需要运行时,这样用户就能获得更快的加载体验。

每种框架都有一些微妙之处,使其更容易受到最终用户会遇到的特定错误类别(通常与状态管理或变更检测有关)的影响。

原文:https://www.jdon.com/67402.html

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

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

相关文章

IntelliJ IDEA2023中利用maven-archetype-quickstart模板创建项目无src文件夹及maven插件下载过慢问题的解决

目录 介绍问题之解决问题2的解决问题1的解决 介绍 昨天下载并安装了IntelliJ IDEA 2023的最新版&#xff08;以下简称为IDEA 2023&#xff09;&#xff0c;学习利用该IDE编写Java项目及将其与maven结合构建项目。我所安装的maven是去年暑假安装的&#xff0c;版本为Apache Mav…

linux系统如何使用GPT工具进行分区

GPT&#xff08;GUID Partition Table&#xff09;是一种用于硬盘分区的新分区表格式&#xff0c;它具有比旧的MBR&#xff08;Master Boot Record&#xff09;分区表更高的灵活性和可靠性。在Linux系统中&#xff0c;我们可以使用GPT工具进行分区操作&#xff0c;本文将对如何…

linux常用命令—— less、more、head、cat

文章目录 1、less&#xff1a;向前或向后查看文件内容&#xff08;推荐使用&#xff09;1.1、less 基本用法1.2、快捷键操作1.3、查找文件中的关键字使用说明 1.4、linux中 less和more 的区别 2、more&#xff1a; 分页显示文件内容3、head&#xff1a;查看文件开头的内容4、ca…

认识主被动无人机遥感数据、预处理无人机遥感数据、定量估算农林植被关键性状、期刊论文插图精细制作与Appdesigner应用开发

目录 第一章、认识主被动无人机遥感数据 第二章、预处理无人机遥感数据 第三章、定量估算农林植被关键性状 第四章、期刊论文插图精细制作与Appdesigner应用开发 更多推荐 遥感技术作为一种空间大数据手段&#xff0c;能够从多时、多维、多地等角度&#xff0c;获取大量的…

[SQL挖掘机] - 删除数据库

介绍: 使用 SQL 中的 drop database命令。它会删除指定的数据库及其所有相关的表、视图、索引等对象。 使用命令: 下面是 drop database命令的基本语法&#xff1a; drop database database_name;其中&#xff0c;database_name是要删除的数据库的名称。 请注意&#xff0…

【数据结构常见七大排序(一)】—插入排序篇【直接插入排序】And【希尔排序】

目录 1.排序的概念及其运用1.1排序的概念1.2排序运用​​​​​​​​​​​​​​​​​​​​​1.3常见的七大排序 ​​2.直接插入排序2.1基本思想​​2.2直接插入排序2.3动图助解2.4直接插入排序源码​2.5直接插入排序的特性总结 ​​3.希尔排序( 缩小增量排序 )​​3.1希尔…

STM32CubeMX X-CUBE-AI更新模型

如题&#xff0c;我采用一个采用stm32CUBEMX生成了工程&#xff0c;工程里面使用了X-CUBE-AI对自定义的模型进行模型压缩&#xff0c;但是我经常要更新模型&#xff0c;那么怎样更新模型了。这里开博客记录一下。 如图所示&#xff0c;为基于STM32CUBEMX生成的工程文件目录结构…

C/C++ 程序 IDE 开发工具 CLion

下载地址&#xff1a; https://www.jetbrains.com/clion/ https://www.jetbrains.com/clion/ 下载地址&#xff1a; https://www.jetbrains.com/clion/download/ https://www.jetbrains.com/clion/download/ 历史版本&#xff08;老版本&#xff09;下载地址&#xff1a; h…

TCP/IP网络编程 第二十章:Windows中的线程同步

同步方法的分类及CRITICAL_SECTION同步 用户模式&#xff08;User mode)和内核模式&#xff08;Kernal mode&#xff09; Windows操作系统的运行方式是“双模式操作”&#xff08;Dual-mode Operation&#xff09;,这意味着Windows在运行过程中存在如下2种模式。 □用户模式&…

【分布式学习】服务注册与发现:Eureka、zk、Nacos、Consul对比

服务发现框架对比 –NacosEurekaConsulCoreDNSZookeeper一致性协议CPAPAPCP—CP健康检查TCP/HTTP/MYSQL/Client BeatClient BeatTCP/HTTP/gRPC/Cmd—Keep Alive负载均衡策略权重/metadata/SelectorRibbonFabioRoundRobin—雪崩保护有有无无无自动注销实例支持支持不支持不支持…

预处理过程(2/13)

头文件包含&#xff1a;#include定义一个宏&#xff1a;#define条件编译&#xff1a;#if、#else、#endif编译控制&#xff1a;#pragma 编译器提供的这些预处理命令&#xff0c;大大方便了程序的编写&#xff1a;通过头文件包含可以实现模块化编程&#xff1b;使用宏可以定义一…

关于正则表达式的简单介绍以及使用

一、介绍 正则表达式通常被用来检索匹配某种模式&#xff08;规律&#xff09;的文本 日常文本检索&#xff0c;如果单纯检索某个数字&#xff0c;字母&#xff0c;或者单词匹配出来的结果较多&#xff0c;而面对目标文件内容较大的时&#xff0c;我们也不可能肉眼对检索出来的…

JavaCV error AAC with no global headers is currently not supported

当我使用JavaCV库&#xff08;FFmpegFrameGrabber FFmpegFrameRecorde&#xff09;尝试将dhav码流转为rtsp的时候&#xff0c;出现了以下报错&#xff1a; Error: [rtsp 0000002318df7c30] AAC with no global headers is currently not supported.Exception in thread &quo…

leetcode 542. 01 矩阵

给定一个由 0 和 1 组成的矩阵 mat &#xff0c;请输出一个大小相同的矩阵&#xff0c;其中每一个格子是 mat 中对应位置元素到最近的 0 的距离。 两个相邻元素间的距离为 1 。 示例 1&#xff1a; 输入&#xff1a;mat [[0,0,0],[0,1,0],[0,0,0]] 输出&#xff1a;[[0,0,0],…

docker安装yapi

一&#xff1a;创建docker-compose.yml 创建docker-compose.yml文件&#xff0c;具体内容如下&#xff1a; version: 3services:yapi-web:image: jayfong/yapi #拉取镜像container_name: yapi-web #容器名称ports: - 3000:3000 #端口映射environment:- YAPI_ADMIN_ACCOUN…

解锁新技能《logback packagingData属性配置作用及源码分析》

开源SDK: <dependency><groupId>io.github.mingyang66</groupId><artifactId>oceansky-logger</artifactId><version>4.3.6</version> </dependency> <!-- 基于logback的日志组件SDK --> <dependency><grou…

Hadoop——Hadoop单机搭建问题汇总

1、org.apache.hadoop.security.AccessControlException: Permission denied: userroot... 解决方法&#xff1a;关闭Hadoop,在hdfs-site.xml文件中添加&#xff1a; <property><name>dfs.permissions</name><value>false</value> </proper…

【Unity2D】设置一物体默认在其他物体之上不被遮挡

比如我想让机器人显示在箱子的前面。 点击箱子&#xff0c;将其层级设置在机器人的后面。 即修改箱子的Order in Layer 在机器人之后 物体默认的Order in Layer 都是0 &#xff0c;将箱子的Order in Layer修改为-1即可 这样将确保先绘制机器人&#xff0c;然后绘制箱子。这样…

C#鼠标拖拽,移动图片实例

最近工作需要做一个鼠标可以拖拽移动图片的功能。 写了几个基本功能&#xff0c;勉强能用。这里记录一下。欢迎大神补充。 这个就是完成的功能。 下边的绿色是一个pictureBox&#xff0c;白色框也是一个pictureBox&#xff0c;他们二者是子父级关系。 绿色是父级&#xff0c…

【图论】最短路算法

1、Dijkstra算法 不能处理边权为负的情况&#xff0c;复杂度O(nlogn) 步骤与基本思路 &#xff08;1&#xff09;初始化距离数组dist[N]&#xff0c;将其所有值赋为0x3f&#xff0c;并将起点1的dist初始化为0&#xff0c;存入优先队列heap中 &#xff08;2&#xff09;从所…