react和react2_React性现代化

react和react2

Reactive programming has taken JavaScript by storm over the last decade, and for good reason; front-end development greatly benefits from the simplicity of writing user interface code that "reacts" to data changes, eliminating substantial error-prone imperative code tasked with updating UIs. However, while the popularity has increased, tools and techniques have not always kept up with modern browser functionality, web APIs, language capabilities, and optimal algorithms for performance, scalability, syntactic ease, and long-term stability. In this post, let's look at some of the newer technologies, techniques, and capabilities that are now available, and demonstrate these in the context of a new library, Alkali.

在过去的十年中,响应式编程席卷了JavaScript,这是有充分理由的。 前端开发极大地受益于编写“响应”数据更改的用户界面代码的简便性,从而消除了用于更新UI的大量容易出错的命令性代码。 但是,尽管流行度有所提高,但工具和技术并不能总是与现代浏览器功能,Web API,语言功能以及用于性能,可伸缩性,语法易用性和长期稳定性的最佳算法保持一致。 在这篇文章中,让我们看一下现在可用的一些较新的技术,技巧和功能,并在一个新的库Alkali的背景下进行演示。

The techniques we will look at include queued rendering, pull-based granular reactivity, reactive ES6 generators and expressions, reactive native web components, and reversible directional flow. These approaches are more than just fad-driven progamming, they are the result of adopted browser technologies and incremental research and development that produce better performance, cleaner code, inter-operability with future components, and improved encapsulation.

Again, we will be looking at Alkali for examples of resulting simple succinct declarative style (you can jump ahead see the Alkali todo-mvc application for a more complete example) with standard native element architecture and perhaps the most important feature we can build: fast performance with minimal resource consumption. These modern techniques really do yield substantial performance, efficiency, and scalability benefits. And with the constant churn of new libraries, the most prescient and stable architecture is building directly on the standards-based browser element/component API.

我们将研究的技术包括排队渲染,基于拉式的粒度React性,React式ES6生成器和表达式,React式本机Web组件以及可逆的定向流。 这些方法不仅仅是流行驱动的编程,它们是采用的浏览器技术和不断研发的结果,可以产生更好的性能,更干净的代码,与未来组件的互操作性以及改进的封装。 再次,我们将在Alkali上查看产生的简单简洁声明式样式的示例(您可以跳到Alkali todo-mvc应用程序中获得更完整的示例),它具有标准的本机元素架构,并且也许是我们可以构建的最重要的功能:快速最小的资源消耗的性能。 这些现代技术确实可以带来实质性的性能,效率和可伸缩性优势。 随着新库的不断更新,最先行和稳定的体系结构直接建立在基于标准的浏览器元素/组件API上。

推挽式激活 (Push-Pull Reactivitiy)

A key to scaling reactive programming is the architectural flow of data. A naive approach to reactivity is to use a simple observable or listener pattern to push every update through a stream with every evaluation to every listener. This quickly can results in excessive computations in any type of multiple-step state update that leads to unnecessarily repeated intermediate evaluations. A more scalable approach is to use "pull"-based approach, where any computed data is calculated lazily when downstream observer requests or "pulls" the latest value. Observers can request data using de-bouncing or queuing after being notified that dependent data has changed.

扩展React式编程的关键是数据的体系结构流。 天真的React性方法是使用简单的可观察或侦听器模式,将每个更新通过流向每个侦听器推送每个评估。 这会很快导致在任何类型的多步状态更新中进行过多的计算,从而导致不必要的重复中间评估。 一种更具可扩展性的方法是使用基于“拉”的方法,其中,当下游观察者请求或“拉”最新值时,将延迟计算所有计算数据。 观察者在收到相关数据已更改的通知后可以使用反跳或排队请求数据。

A pull-based approach can also be used in conjunction with caching. As data is computed, results can be cached, and notifications of upstream changes can be used to invalidate downstream caches to ensure freshness. This cache and invalidation scheme of pull-based reactivity follows the same design architecture as REST, the scalable design of the web, as well as the architecture of modern browser rendering processes.

基于拉的方法也可以与缓存结合使用。 计算数据时,可以缓存结果,并且可以使用上游更改的通知来使下游缓存无效,以确保新鲜度。 这种基于拉式React性的缓存和失效方案遵循与REST相同的设计架构,Web的可伸缩设计以及现代浏览器呈现过程的架构。

There are, however, situations where it is preferable to have certain events be "pushed" where they incrementally update the current state. This is particularly useful for progressive updates to collection where items can be added, removed, or updated without propagating an entire collection state. The most broadly performant approach is a hybrid: data flow is primarily is pulled from the observer, but incremental updates can be pushed through live data flows as an optimization.

但是,在某些情况下,最好“推”某些事件,使它们逐步更新当前状态。 这对于逐步更新集合非常有用,其中可以在不传播整个集合状态的情况下添加,删除或更新项目。 性能最广泛的方法是混合:将数据流主要从观察者中拉出,但可以通过实时数据流将增量更新作为优化进行推送。

排队渲染 (Queued Rendering)

The key to leveraging pull-based reactive dependencies for efficiency in reactive applications is ensuring that rendering execution is minimized. Frequently, multiple parts of an application may update the state of the application, which can easily lead to thrashing and inefficiency if rendering is synchronously executed immediately on any state change. By queuing the rendering we can ensure that even when multiple state changes occur, rendering is minimized.

在响应式应用程序中利用基于拉式的响应式依赖来提高效率的关键是确保最小化渲染执行。 通常,应用程序的多个部分可能会更新应用程序的状态,如果在任何状态更改后立即立即立即执行渲染,则很容易导致系统崩溃和效率低下。 通过对渲染进行排队,我们可以确保即使发生多个状态更改,也可以最小化渲染。

Queuing actions or de-bouncing is a relatively common and well-known technique. However, for optimal queuing of rendering, browsers actually provide an excellent alternative to generic de-bouncing functions. Due to its name, requestAnimationFrame is often relegated to animation libraries, but this modern API is actually perfect for queuing up rendering of state changes. requestAnimationFrame is a macro event task, so any micro tasks, like promise resolutions will be allowed to complete first. It also allows browsers to determine precisely the best timing to render new changes, taking into consideration the last rendering, tab/browser visibility, current load, etc. The callback can be executed without delay (usually sub-millisecond) in resting visible state, at an appropriate frame rate in sequential rendering situations, and even completely deferred when a page/tab is hidden. In fact, by queuing state changes with requestAnimationFrame, and rendering them as needed for visual update, we are actually following the same optimized rendering flow, precise timing, and sequence/path that modern browsers themselves use. This approach ensures that we are working in a complementary way with browsers to render efficiently and timely, without incurring extra layouts or repaints.

排队动作或反跳是一种相对普遍且众所周知的技术。 但是,对于最佳的渲染排队,浏览器实际上提供了通用反跳功能的绝佳替代方案。 由于其名称, requestAnimationFrame通常被放到动画库中,但是这个现代的API实际上非常适合排队状态更改的呈现。 requestAnimationFrame是一个宏事件任务,因此任何微任务(如promise决议)都将被允许先完成。 此外,浏览器还可以根据最近的渲染,标签/浏览器的可见性,当前的负载等情况,准确确定最佳的时间来进行新的更改。在静止的可见状态下,回调可以无延迟(通常为亚毫秒)地执行,在顺序渲染的情况下以适当的帧速率播放,甚至在隐藏页面/标签时完全推迟。 实际上,通过使用requestAnimationFrame状态更改进行排队,并根据视觉更新的需要对其进行渲染,我们实际上遵循的是现代浏览器自身使用的相同的优化渲染流程,精确的时间安排和顺序/路径。 这种方法可确保我们以与浏览器互补的方式工作,以高效且及时地进行渲染,而不会产生额外的布局或重新绘制。

This can be thought of as a two-phrase rendering approach. The first phase is a response to event handlers where we update canonical data sources, which triggers the invalidation of an derived data or components that rely on that data. All invalidated UI components are queued for rendering. The second phase is the rendering phase where components retrieve their necessary data and render it.

可以将其视为两阶段渲染方法。 第一阶段是对事件处理程序的响应,在此我们更新规范数据源,这将触发派生数据或依赖于该数据的组件的失效。 所有无效的UI组件都排队等待渲染。 第二阶段是渲染阶段,其中组件检索其必要的数据并进行渲染。

Alkali leverages this rendered queuing through its renderer objects, that connect reactive data inputs (called "variables" in alkali) to an element, and then queues all state changes for re-rendering through the requestAnimationFrame mechanism. This means any data bindings are connected to queued renderings. This can demonstrated by creating a reactive value with the Variable constructor, and connecting this to an element (here we create a <div>). Let's look at some example code:

Alkali通过其渲染器对象利用此渲染队列,该渲染器对象将React性数据输入(碱中称为“变量”)连接到元素,然后将所有状态更改排队,以便通过requestAnimationFrame机制进行重新渲染。 这意味着所有数据绑定都连接到排队的渲染。 这可以通过使用Variable构造函数创建React性值并将其连接到元素(在此我们创建<div> )来证明。 让我们看一些示例代码:


import { Variable, Div } from 'alkali'

// create a variable
var greeting = new Variable('Hello')
// create div with the contents connected to the variable
body.appendChild(new Div(greeting)) // note that this is a standard div element
// now updates to the variable will be reflected in the div
greeting.put('Hi')
// this rendering mechanism will be queue the update to the div
greeting.put('Hi again')


This connection will automatically update the div using the requestAnimationFrame mechanism anytime the state changes, and multiple updates will not cause multiple renderings, only the last state will be rendered.

每当状态更改时,此连接将使用requestAnimationFrame机制自动更新div,并且多次更新不会导致多次渲染,仅会渲染最后一个状态。

颗粒React性 (Granular Reactivity)

Pure functional reactivity programming allows individual signals or variables to be used and propagated through a system. However, in the interest of maintaining the familiarity of imperative programming, diff-based reactive frameworks like ReactJS, that use a virtual DOM, have become very popular. These allow applications to be written in the same way we might write an application with imperative code. When any application state changes, components simply re-render, and once completed the component output is diffed with previous output to determine the changes. Rather than explicit data flows that generate specific changes to the rendered UI, diffing compares the output of re-execution with previous states.

纯功能React性编程允许使用单个信号或变量,并通过系统进行传播。 但是,为了保持对命令式编程的了解,使用虚拟DOM的基于diff的React式框架(如ReactJS)已变得非常流行。 这些允许以与编写带有命令性代码的应用程序相同的方式来编写应用程序。 当任何应用程序状态发生变化时,组件只需重新渲染即可,一旦完成,组件输出就会与之前的输出进行比较以确定更改。 差异不是将显式的数据流生成对呈现的UI的特定更改,而是将重新执行的输出与以前的状态进行比较。

While this can produce a very familiar and convenient paradigm for coding, it comes at a significant cost in terms of memory and performance. Diffing reactivity requires a full copy of rendered output and complex diffing algorithms to determine differences and mitigate excessive DOM rewriting. This virtual DOM typically requires 2 to 3 times the memory usage of a DOM alone, and the diffing algorithms add similar overhead compared to direct DOM changes.

尽管这可以产生非常熟悉和方便的编码范例,但是在内存和性能方面却付出了巨大的代价。 差异React性需要呈现输出的完整副本和复杂的差异算法来确定差异并减轻过多的DOM重写。 该虚拟DOM通常仅需要DOM的2到3倍的内存使用,并且与直接DOM更改相比,差异算法会增加类似的开销。

On the other hand, true functional reactive programming explicitly defines the "variables" or values that can change, and the continuous output of these values as they change. This does not require any additional overhead or diffing algorithms, as the output is directly specified by the relationships defined in the code.

另一方面,真正的函数式React式编程显式定义了可以更改的“变量”或值,以及这些值更​​改时的连续输出。 这不需要任何额外的开销或差异算法,因为输出是由代码中定义的关系直接指定的。

Debuggability also benefits from granular functional reactive code flow. Debugging imperative programming involves recreating conditions and stepping through blocks of code, requiring complex reasoning to evaluate how state changes (and how it is going wrong). Functional reactive flows can be statically inspected, where we always have full visibility to the graph of individual dependent inputs that correspond to UI output, at any point in time.

可调试功能还受益于精细的功能性React式代码流。 调试命令式编程涉及重新创建条件并逐步执行代码块,需要复杂的推理才能评估状态如何变化(以及状态如何出错)。 可以对功能性无功流进行静态检查,在任何时候,我们始终可以完全查看与UI输出相对应的各个从属输入的图。

Again, using true functionally reactive programming techniques is not merely an esoteric or pedantic computer science endeavor, but an approach with meaningful and significant benefits to the scalability, speed, responsiveness, ease of debugging, and flow of your application.

同样,使用真正的功能性React式编程技术不仅是深奥的或根深蒂固的计算机科学,而且是一种对可伸缩性,速度,响应速度,调试简便性和应用程序流程具有有意义且显着优势的方法。

规范和可逆数据 (Canonical and Reversible Data)

The explicit flow of granular reactivity also makes it possible to reverse data flows to achieve two-way bindings, such that downstream data consumers, like input elements, can request upstream data changes without extra configuration, wiring, or imperative logic. This makes it extremely easy to build and bind the input controls in forms.

明确的粒度React流还可以使数据流反向以实现双向绑定,从而使下游数据使用者(如输入元素)可以请求上游数据更改,而无需额外的配置,接线或命令式逻辑。 这使得以表格形式构建和绑定输入控件变得极为容易。

An important principle of reactivity is "single source of truth", where there is an explicit distinction between canonical data sources and derived data. The reactive data can be described as a directed graph of data. This is vital for coherent data management. Synchronizing multiple data states without a clear direction of source and derived data, makes data management confusing and leads to various statement management issues.

React性的重要原则是“单一事实来源”,其中规范数据源与派生数据之间有明显的区别。 React性数据可以描述为数据的有向图。 这对于一致的数据管理至关重要。 同步多个数据状态而没有明确的源数据和派生数据方向,会使数据管理混乱,并导致各种语句管理问题。

Single-directional flow with centralized data changes, associated with diffing reactivity, is one form of a proper directed graph of data. Unfortunately, single-directional flow ultimately means that data consumers must may be manually wired to source data, which typically violates the principle of locality and gradually degrades encapsulation, resulting in increasingly entangled state handling between otherwise separable and independent components, and more complicated form development.

具有差异化React性的,具有集中数据更改的单向流是适当的有向数据图的一种形式。 不幸的是,单向流最终意味着必须将数据使用者手动连接到源数据,这通常违反了本地性原理并逐渐降低了封装性能,导致本来可分离和独立的组件之间的状态处理越来越纠结,并且表单开发更加复杂。

However, a directed graph with canonical source does not necessarily dictate data can only be communicated one way through the graph. With granular reactivity, we can support reversible flow. With reversibility, directionality can still be preserved by defining downstream data changes as a notification of a change that has already been occurred or initiated (in the past), while in contrast, an upstream data change is defined as a request for a change to be initiated (in the future, and revocable). A request for a change to derived data can still be made as long as it has a reverse transform to propagate the request to a source (reversible data traversals or transforms are often called a "lens" in functional terminology). The canonical data change still happens at the data source, even if initiated/requested by a downstream consumer. With this clear distinction of flow, the directed graph of canonical sources and derived data is still preserved, maintaining consistency in state, while still allowing encapsulation in interaction with individual data entities, regardless of whether or not they are derived. In practical terms, this simplifies developing user input and form management, and encourages encapsulation of input components.

但是,具有规范来源的有向图并不一定指示只能通过图以一种方式进行通信。 通过颗粒React,我们可以支持可逆流。 具有可逆性,仍然可以通过将下游数据更改定义为已发生或发起的更改(过去)的通知来保留方向性,而相比之下,上游数据更改被定义为要求更改的请求。发起(将来可以撤销)。 只要具有反向转换以将请求传播到源,就仍然可以请求更改派生数据(在功能术语中,可逆数据遍历或转换通常称为“镜头”)。 即使下游消费者启动/请求,规范数据更改仍会在数据源处发生。 通过明确区分流,仍可保留规范源和派生数据的有向图,保持状态的一致性,同时仍然允许与单个数据实体交互进行封装,无论它们是否派生。 实际上,这简化了开发用户输入和表单管理的工作,并鼓励封装输入组件。

现代DOM扩展(“​​ Web组件”) (Modern DOM Extensions ("Web Components"))

Foresight is critical for the long-term development and maintainability, and this is challenging in the JavaScript ecosystem where numerous technologies are constantly emerging. What new framework will be exciting three years from now? If the past is any indicator, this is very difficult to predict. How do we develop with this type of churn? The most reliable approach is to minimize our reliance on library specific APIs, and maximize our reliance on standard browser APIs and architecture. And with the emerging component APIs and functionality (aka "web components") this is becoming much more feasible.

预见性对于长期的开发和可维护性至关重要,而在不断涌现众多技术JavaScript生态系统中,这具有挑战性。 从现在起三年后,什么新框架会令人兴奋? 如果过去是任何指标,这很难预测。 我们如何发展这种流失? 最可靠的方法是最大程度地减少对库特定API的依赖,并最大程度地提高对标准浏览器API和体系结构的依赖。 随着新兴的组件API和功能(也称为“ Web组件”)的出现,这变得更加可行。

Well-defined reactive structures should not dictate a specific component architecture, and the flexibility to use native or third-party components maximizes possibilities for future development. However, while we can and should minimize coupling, some level of integration can be useful. In particular, being able to directly use variables as inputs or properties is certainly more convenient than having to create bindings after the fact. And, integration with element/component life-cycle, and notification of when elements are removed or detached, can facilitate automatic cleanup of dependencies and listening mechanisms, to prevent memory leaks, minimize resource consumption, and simplify component usage.

定义明确的React式结构不应指示特定的组件体系结构,并且使用本机或第三方组件的灵活性最大程度地提高了未来开发的可能性。 但是,尽管我们可以并且应该最大程度地减少耦合,但一定程度的集成还是有用的。 特别是,能够直接使用变量作为输入或属性肯定比事后创建绑定要方便得多。 并且,与元素/组件生命周期的集成以及何时删除或分离元素的通知,可以促进对依赖项和侦听机制的自动清除,以防止内存泄漏,最小化资源消耗并简化组件使用。

Again, modern browsers have made this type of integration with native elements completely feasible. It is now possible to extend from existing HTML prototypes for real DOM-based custom classes, with reactive variable-aware constructors, and the MutationObserver interface (and potential future web component callbacks) give us the ability to monitor when elements are detached (and attached). The getter/setter functionality introduced in ES5 allows us to properly extend and reproduce native element style properties as well.

同样,现代浏览器使这种与本机元素的集成完全可行。 现在,可以从现有HTML原型扩展为基于DOM的实际自定义类,并具有React性变量感知构造函数,并且MutationObserver接口(以及潜在的未来Web组件回调)使我们能够监视何时分离(并附加)元素)。 ES5中引入的getter / setter功能也使我们能够正确扩展和重现本机元素样式属性。

Alkali defines a set of DOM constructors/classes with exactly this functionality. These classes are minimal extensions to native DOM classes with constructors with arguments that support variable inputs that drive properties, and automated cleanup of variables. In conjunction with lazy/pull-based reactivity, this means elements reactively display data while visible, and once detached, will no longer trigger any evaluations through its dependency of inputs. This results in an element creation and extension with automated self-cleanup of listeners. For example:

Alkali正是使用此功能定义了一组DOM构造函数/类。 这些类是对本机DOM类的最小扩展,这些类具有构造函数,该构造函数的参数支持驱动属性的变量输入和变量的自动清除。 结合基于懒惰/拉动的React性,这意味着元素在可见时会React性地显示数据,并且一旦分离,就不会再因其对输入的依赖性而触发任何评估。 这将导致元素的创建和扩展以及对侦听器的自动自我清理。 例如:


let greetingDiv = new Div(greeting)
body.appendChild(greetingDiv)
// a binding will be created that listens for changes to greeting
...
body.removeChild(greetingDiv)
// binding/listener of greeting will be cleaned up


无功发电机 (Reactive Generators)

Not only do web APIs provide important improvements in our approach to reactivity, the ECMAScript language itself has exciting new features that can be used to improve syntax and ease of writing reactive code. One of the most powerful new features is generators, which provide an elegant and intuitive syntax for interactive code flow. Perhaps the biggest inconvenience of working with reactive data in JavaScript is the frequent need for callback functions for handling state changes. However, ECMAScript's new generator functions provides the ability to pause, resume, and restart a function such that the function can utilize reactive data inputs with standard sequential syntax, pausing and resuming for any asynchronous inputs. Generator controllers can also auto-subscribe to dependent inputs, and re-execute the function when inputs change. This control of function execution that is made possible by generators can be leveraged to yield (pun intended!) an intuitive and easy-to-follow syntax for complex combinations of variable inputs.

Web API不仅在我们的React性方法上提供了重要的改进,而且ECMAScript语言本身还具有令人兴奋的新功能,可用于改善语法并简化编写React性代码的过程。 生成器是最强大的新功能之一,它为交互代码流提供了优雅而直观的语法。 在JavaScript中使用响应数据的最大不便之处可能是经常需要使用回调函数来处理状态更改。 但是,ECMAScript的新生成器功能提供了暂停,恢复和重新启动功能的功能,因此该功能可以利用具有标准顺序语法的React式数据输入,对任何异步输入进行暂停和恢复。 生成器控制器还可以自动订阅相关输入,并在输入更改时重新执行功能。 生成器对函数执行的这种控制可以用于产生(双关语!)直观而易于遵循的语法,以实现变量输入的复杂组合。

Generators have been anticipated for how they eliminate callbacks with promises, and enable an intuitive sequential syntax. But generators can be taken even further to not only pause and resume for asynchronous input, but restart when any input value changes. This can be accomplished by using the yield operator in front of any variable input, which allows the coordinating code to listen to the variable for changes, and return the current value of the variable to the yield expression when it is available.

人们期望生成器能够消除带有promise的回调,并实现直观的顺序语法。 但是,生成器甚至可以进一步扩展,不仅可以暂停和恢复异步输入,还可以在任何输入值更改时重新启动。 这可以通过在任何变量输入之前使用yield运算符来实现,它允许协调代码侦听变量的更改,并在变量可用时将变量的当前值返回给yield表达式。

Let's take a look at how this is accomplished. In Alkali, generator functions can be used as a transform for input variables, to create a reactive function that outputs a new composite variable with the react. The react function acts as a generator controller to handle reactive variables. Let's break down an example of this:

让我们看一下这是如何完成的。 在Alkali中,生成器函数可用作输入变量的转换,以创建一个React函数,该函数输出带有react的新复合变量。 react函数充当生成器控制器来处理React变量。 让我们分解一个例子:


let a = new Variable(2)
let aTimesTwo = react(function*() {
  return 2 * yield a
})

The react controller handles executing the provided generator. A generator function returns an iterator that is used to interact with the generator, and react starts the iterator. The generator will execute until it evaluates a yield operator. Here, the code will immediately encounter the yield operator, and return control to the react function with the value provided to the yield operator returned from the iterator. In this case, the a variable will be returned to the react function. This gives the react function the opportunity to do several things.

react控制器处理执行提供的生成器。 生成器函数返回一个迭代器,该迭代器用于与生成器进行交互,并react以启动迭代器。 生成器将执行直到评估yield运算符。 在这里,代码将立即遇到yield运算符,并使用从迭代器返回给yield运算符的值将控制返回给react函数。 在这种情况下, a变量将返回到react函数。 这使react函数有机会做几件事。

First, it can subscribe or listen to the provided reactive variable (if it is one), so it can react to any changes by re-executing. Second, it can get the current state or value of the reactive variable, so it can return that back as the result of yield expression, when resuming. Finally, before returning control, react function can check if the reactive variable is asynchronous, holding a promise to value, and waiting for the promise to resolve before resuming execution, if necessary. Once the current state is retrieved, the generator function can be resumed with value of 2 returned from the yield a expression. If more yield expressions are encountered they will be sequentially resolved in the same way. In this case, the generator will then return a value of 4, which will end the generator sequence (until a changes and it is re-executed).

首先,它可以订阅或侦听所提供的React变量(如果为一个),因此可以通过重新执行对任何更改作出React。 其次,它可以获取React变量的当前状态或值,因此在恢复时可以将其作为yield表达式的结果返回。 最后,在返回控制之前, react函数可以检查React变量是否异步,持有对值的承诺,并在必要时在恢复执行之前等待该承诺的解析。 一旦检索到当前状态,就可以恢复生成器函数,并从yield a表达式返回2值。 如果遇到更多的yield表达式,它们将以相同的方式顺序解析。 在这种情况下,发电机将则返回的值4 ,这将结束该序列发生器(直至a变化,它是重新执行)。

With the alkali react function, this execution is encapsulated in another composite reactive variable, and any variable changes will not trigger re-execution until downstream data accesses or requests it.

使用碱react功能,此执行将封装在另一个复合React变量中,并且任何变量更改都不会触发重新执行,直到下游数据访问或请求它为止。

Alkali generator functions can also be used directly in element constructors to define a rendering function that will automatically re-execute whenever an input value changes. In either case, we then use the yield in front of any variable. For example:

碱生成器函数也可以直接在元素构造函数中使用,以定义呈现函数,只要输入值发生变化,该函数就会自动重新执行。 无论哪种情况,我们都在任何变量前使用yield 。 例如:


import { Div, Variable } from 'alkali'
let a = new Variable(2)
let b = new Variable(4)
new Div({
  *render() {
    this.textContent = Math.max(yield a, yield b)
  }
})

This creates a <div> with a text content of 4 (the maximum of the two input values). We could update either variable, and it will re-execute:

这将创建一个<div> ,其文本内容为4 (两个输入值的最大值)。 我们可以更新任何一个变量,它将重新执行:


a.put(5)

The <div> would now be updated to have a content of 5.

<div>现在将被更新为具有5的内容。

Generators are not universally available in all browsers (not in IE and Safari), but generators can be transpiled and emulated (with Babel or other tools).

生成器并非在所有浏览器中都通用(不是在IE和Safari中),但是可以对生成器进行编译和仿真(使用Babel或其他工具)。

属性和代理 (Properties and Proxies)

Reactively binding to properties of object is an important aspect of reactivity. But to encapsulate a property with notification of changes, requires more than just the current property value returned by standard property access. Consequently, reactive property bindings or variables can require verbose syntax.

React性地结合到物体的性质是React性的重要方面。 但是要封装具有更改通知的属性,不仅需要标准属性访问返回的当前属性值。 因此,React性属性绑定或变量可能需要冗长的语法。

However, another exciting new feature in ECMAScript is proxies, which allows us to define an object that can intercept all property access and modifications with custom functionality. This is powerful functionality, that can be used to return reactive property variables through ordinary property access, enabling convenient, idiomatic syntax with reactive objects.

但是,ECMAScript中另一个令人兴奋的新功能是代理,它使我们能够定义一个对象,该对象可以拦截所有属性访问和使用自定义功能进行的修改。 这是强大的功能,可用于通过普通属性访问返回React性属性变量,从而对React性对象启用方便的惯用语法。

Unfortunately proxies are not so easily emulated through code compilers like Babel. Emulating proxies would require not only transpiling the proxy constructor itself, but any code that might access the proxy, so emulation without native language support would either be incomplete or unreasonably slow and bloated due to the massive transpilation required of every property access in an app. But more targeted transpilation of reactive code is possible. Let's look at that.

不幸的是,像Babel这样的代码编译器并不容易模拟代理。 模拟代理不仅需要转换代理构造函数本身,还需要转换可能访问该代理的任何代码,因此,由于没有对本机语言的支持,因此对应用程序中每个属性访问的大量转换都将导致模拟不完整或不合理地缓慢且肿。 但是可以对React性代码进行更有针对性的转换。 让我们看看。

React式 (Reactive Expressions)

While the EcmaScript is constantly advancing, tools like Babel and its plugin capability, give us tremendous opportunities for creating new compiled language features. And while generators are awesome for creating a function with series of steps that can execute asynchronously and re-execute reactively, with a Babel plugin, code can be transformed to actually create fully reactive data flows, with property bindings, using ECMAScript syntax. This goes further than simply re-execution, but the output of expressions can be defined in relation to inputs such that reversible operators, reactive properties, and reactive assignments can be generated using simple, idiomatic expressions.

在EcmaScript不断发展的同时,Babel等工具及其插件功能为我们提供了创建新的编译语言功能的巨大机会。 尽管生成器非常棒,可以使用Babel插件创建具有一系列可以异步执行并以响应方式重新执行的步骤的功能,但可以使用ECMAScript语法将代码转换为实际创建具有属性绑定的完全响应式数据流。 这不仅可以简单地重新执行,还可以相对于输入定义表达式的输出,从而可以使用简单的惯用表达式生成可逆的运算符,React性和React性赋值。

A separate project houses an alkali-based babel plugin for transforming reactive expressions. With this we can write a normal expression as an argument to a react call/operator:

一个单独的项目提供了一个基于碱的babel插件,用于转换React表达式。 这样,我们可以编写一个正则表达式作为react调用/运算符的参数:


let aTimes2 = react(a * 2)

This aTimes2 will be bound to the multiplication of the input variable. If we change the value of a (using a.put()), aTimes2 will auto-update. But because this is actually two-way binding through a well-defined operator, the data is reversible as well. We can assign a new value to aTimes2 of 10, then a will be updated to a value of 5.

aTimes2将绑定到输入变量的乘法。 如果我们改变的值a (使用a.put() aTimes2将自动更新。 但是由于这实际上是通过定义明确的运算符进行的双向绑定,因此数据也是可逆的。 我们可以在新的值赋给aTimes210 ,然后a将被更新为值5

As mentioned, proxies are nearly impossible to emulate across a whole code-base, but within our reactive expressions, it is very reasonable to compile property syntax to handle properties as reactive variables. Furthermore, other operators can be transpiled to reversible transformations of variables. For example, we could write complex combinations with fully reactive, language-level code:

如前所述,几乎不可能在整个代码库中模拟代理,但是在我们的React表达式中,编译属性语法以将属性作为React变量来处理是非常合理的。 此外,可以将其他运算符转换为变量的可逆转换。 例如,我们可以使用完全React性的语言级代码编写复杂的组合:


let obj, foo
react(
  obj = {foo: 10}, // we can create new reactive objects
  foo = obj.foo, // get a reactive property
  aTimes2 = foo // assign it to aTimes2 (binding to the expression above)
  obj.foo = 20 // update the object (will reactively propagate through foo, aTimes2, and to a)
)
a.valueOf() // -> 10


现代化 (Modernizing)

Web development is an exciting world of constant change and progress. And reactivity is a powerful programming concept for sound architecture of advance applications. Reactivity can and should grow to use the latest new technologies and capabilities of the modern browser and its language and APIs. Together they can yield another step forward in web development. I am excited for the possibilities, and hope these ideas can advance the ways we can leverage the future with new tools.

Web开发是一个不断变化和进步的令人兴奋的世界。 React性是高级应用程序健全体系结构的强大编程概念。 React性可以并且应该发展为使用现代浏览器及其语言和API的最新新技术和功能。 他们在一起可以使Web开发迈出新的一步。 我为这种可能性感到兴奋,并希望这些想法能够推动我们利用新工具来利用未来的方式。

Alkali has been developed as our engineering team, at Doctor Evidence, has been working to build interactive and responsive tools for exploring, querying, and analyzing large data sets of clinical medical studies. It has been a fascinating challenge to maintain a smooth and interactive UI with complex and vast data, and many of these approaches have been very useful for us, as we adopt newer browser technologies in developing our web software. If nothing else, hopefully Alkali can serve as an example to inspire more steps forward in web development.

Alkali的发展是作为Evidence博士的工程团队开发的,一直致力于构建交互式和响应式工具,以探索,查询和分析临床医学研究的大数据集。 维持复杂且庞大的数据的流畅且交互式的UI一直是一个令人着迷的挑战,并且随着我们在开发Web软件时采用更新的浏览器技术,这些方法中的许多方法对我们非常有用。 如果没有别的,希望Alkali可以作为一个例子,激发Web开发方面的更多进步。

翻译自: https://davidwalsh.name/modernization-reactivity

react和react2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值