Space Cowboy

生死去来 棚头傀儡 一线断时 落落磊磊

0%

简述

事实上,响应式并不是 Vue3 的新概念,它是一个核心概念。在实际代码中,响应式系统经常与组件化相提并论。更进一步的说,组件化赋予了开发者模块化代码的能力,而响应式系统则让开发者可以通过数据控制组件的呈现方式。

不过这东西从本质上来讲,其实就是劫持数据的变化,在数据变化后自动的执行一些副作用函数。

如果你大致的了解过这个东西,你大概会知道,Vue2Vue3 的响应式系统实现有些略微不同。
从表象上来说,Vue2 的响应式系统是黑盒。Vue2 承包了一切工作,你只需要将数据定义在诸如 datapropscomputed 等选项中就行。而 Vue3 则是把这个决定权交给了开发者。由开发者来决定究竟哪些数据应该是响应式的。
从实现上来说,Vue2 使用 Object.defineproperty 来实现数据劫持,而 Vue3 则使用了 proxy

从逻辑上讲,其实二者是相同的,都是为了实现核心的数据劫持。
不过 Vue 毕竟是一个投入到实际生产中使用的框架,仅仅完成理论上的实现当然是不行的。从 Object.definepropertyproxy 的切换实际上也表现出了一些技术上的选择。

简单来说,因为 Vue2 对响应式数据黑盒化的设计,在框架初始化的时候,会递归遍历所有数据,然后使用 Object.defineproperty 来做劫持。这是一个解决方案,但并不够好。因为首先会付出很多性能消耗,其次,并不是每一条数据都需要变成响应式的。递归消耗的性能支出是否合算,全看开发者的具体实现方式。另外,Object.defineproperty 也不能监听到对象属性的新增与删除。
所以 Vue3 使用了 proxy 和显式的 reactice API。这样不仅可以让开发者自行决定哪些数据需要变成响应式的,还能减少劫持时的数据消耗。

除此之外,在具体实现中,Vue3 也做了一些调整来优化性能。更具体的东西,来直接看源码吧。

阅读全文 »

一些说明

  1. 这篇文章并不是专注于介绍响应式 API 的文章,所以如果你想搞清楚新的 API 该怎么用,那么你应当关注官方的 Migration Guide
  2. 为了更明确的说明一些问题,我可能会删减许多代码。但这些代码并非是不必要的,只是对于我们要阐述的主题来说,它们是毫无必要的

从 CreateApp 开始

在这一节,我们会介绍 Vue.js 的入口函数 createApp,以及这之后的一整套渲染过程。阅读这一部分的内容有助于你理解响应式系统在整个 Vue.js 中扮演了怎样的角色。

当你使用 Vue3 写一个组件时,你可能会这样做:

1
2
3
const vm = createApp({
// ...
}).mount("#app");
阅读全文 »

工欲善其事必先利其器,在阅读源码前,首先要做的一步就是搭建调试源码的环境。

  1. Github 下载源码:
1
git clone git@github.com:vuejs/vue-next.git
  1. 使用 Webstrom 打开项目,安装依赖
1
yarn install
  1. 配置项目运行

你可以参考我的配置,但请注意将一些个性化设置配置成你自己的。
注意 Arguments 一栏的参数 -s。这个参数会生成 source map 来帮助你调试源码。

Vue3 源码运行配置

阅读全文 »

关于 Treeshaking

tree shaking 指的是移除 JavaScript 上下文中的的未引用代码(dead-code)。这个术语和概念最先是 ES2015 打包工具 rollup 发展的。

事实上,消除无用代码并不是一个新的概念。这种技术被广泛运用于传统的编程语言编译器中,编译器会判断代码是否影响功能,并移除那些无用的代码,这个技术被称为 DCE (dead code elimination)

从先后来讲,tree shakingDCE 的一种新的实现。不过和传统的 DCE 不一样的是,tree shaking 更关注于消除没有用到的代码,而 DCE 则关注那些不可能执行的代码,由编译器将 dead code 从 AST 上删除。
另一方面,在大多数情况下,JavaScript 都是通过网络加载的。众所周知,网络速度可是一个变化多端的东西。所以如果能缩短代码的加载时间,那么这对网络应用性能和用户体验的提升都是极大的。

阅读全文 »

本文是 Node.js Streams: Everything you need to know 一文的笔记

流是 Nodejs 中最棒的,同时也是最被人误解的想法。
—— Dominic Tarr

如果想要学习 Nodejs,那么 这个概念就是无法绕过的重点。在 Nodejs 中,很多内建模块都实现了流接口。例如常见的 requestzlib 等。
那么, 到底是什么呢?
简单来说,流是一组数据的集合。但在使用它时,程序并不会一次性的将其载入内存中使用,而是逐端使用数据。显然,这种数据类型有助于处理大体积数据,或是从外部来源逐段发来的数据。对于后者,一个常见的例子就是处理 WebStocket 接口的时候。

阅读全文 »

参考:深入学习 Node.js Buffer

关于 Buffer

BufferNode.js 的核心模块,它使得开发者可以在 TCP 流或是文件系统操作等场景中处理二进制数据。
Buffer 的大小是固定的,且无法调整。它在 V8 堆外分配物理内存。

V8 是一个由 Google 开发的开源 JavaScript 引擎,用于 Google Chrome 及 Chromium 中。

常见的应用是在 中使用。流是一组数据的集合。在一般情况下,流的生产者和消费者的速度是不一致的,所以我们需要 Buffer 来缓存数据。

阅读全文 »

本文翻译自 SwiftUI: @State vs @StateObject vs @ObservedObject vs @EnvironmentObject

SwiftUI 开发者们需要做的第一个决定就是,应该选择哪个有效的属性包装器来存储数据。特别是在 IOS 14 中,整个应用的生命周期 都可以使用 SwiftUI 来开发,用正确的方式存储应用的数据是确保应用正常运行,避免 bug 的前提。

在使用 SwiftUI 制作 app 时,一个坑就是 @State@StateObject@ObservedObject@EnvironmentObject 这几个属性包装器从表面上来看,都是能够运行的。应用程序会被正常编译,甚至还能得到你想要的行为,即使你用错了属性包装器。又不是不能用

但是,假如用错了,你可能会发现当你更新数据时,UI 却不会随之正常更新。

那么在这篇文章里,我们就来解决这些问题。我们先从 @State 开始。

阅读全文 »

本文翻译自 Error Handling in Swift Combine Framework,稍作修改

错误处理策略

在计算机编程中,错误是不可避免的。我们不可能要求一段程序永远不出错,但我们需要一些手段来让程序可以尽快的从错误中恢复过来。让我们看看在 Combine 框架中该怎么处理。

终止 APP

最直接的错误处理就是不处理错误。当然了,我们不可能将这样的代码直接交付给客户。不过在开发过程中,这个策略是很有用的。我们希望在开发中应用越早崩溃越好,这样我们才能发现代码中的错误。
另外,这里还有两个不需要担心错误处理的场景:

  • 在编写实验代码时
  • 在教授或者学习时

Combine 为这个目的提供了 assertNoFailure(_ : file : line :) 方法。它会在前一个 Publisher 发出错误前停止 app,通知打印调试信息帮助你解决问题。

如果你确定在你的流中不会出现出错,你可以把发布者的 Failure 类型设置为 Never。它在语法上禁止错误,它比 assertNoFailure(_ : file : line :) 安全得多,后者可能会使你的 app 崩溃

阅读全文 »

这篇文章基本翻译自 Swift Combine Framework Tutorial: Getting Started,删除了一些重复的内容

Combine 的使用

前面两篇文章已经系统的介绍了 Combine 框架的主要组件。在这篇文章中,我们将会介绍一下它们的基本用法。如何将各种内建组件组合起来形成一套逻辑链。

Publisher 与 Subscriber 的连接

Combine 有两个内建的 SubscriberSubscribers.SinkSubscribers.Assign。你可以通过调用 Publisher 上任何一个方法来连接它们:

  • sink(receiveCompletion: receiveValue:) 在闭包中处理新元素或是完成事件
  • assign(to: on:) 将新元素写入属性
1
2
3
4
5
6
7
8
9
10
let publisher = Just(1)

publisher.sink(
receiveCompletion: { _ in
print("finished")
},
receiveValue: { value in
print(value)
}
)
  1. 创建一个 Just 发布者,仅发送一个值,然后完成。Combine 有一堆内建的 Publisher,包括 Just
  2. 连接到 Subscribers.Sink 订阅者
阅读全文 »

本文翻译自 Understanding Schedulers in Swift Combine Framework 。你可以阅读原文或者是原作者的 Combine 框架系列以了解更多内容。
另外的,上一篇文章介绍了 PublisherSubscriberSubject。这篇关于 Scheduler 的文章算是一个补充。在日常的开发中,真实的 Publisher 需要借助 Scheduler 基于时序进行产出——译者注

现在,我们已经了解了 Combine 框架的 全景。现在是时候学习 scheduler 的知识了。

  1. Combine 里内置了哪些 Scheduler
  2. 怎么开关 Scheduler
  3. 如何使用 Combine 来执行异步工作?
  4. receive(on:)subscribe(on:) 的区别是什么?
阅读全文 »