https://en.wikipedia.org/wiki/Reactive_programminghtml
In computing, reactive programming is a declarative programming paradigm concerned with data streams and the propagation of change. With this paradigm it is possible to express static (e.g., arrays) or dynamic (e.g., event emitters) data streams with ease, and also communicate that an inferred dependency within the associated execution model exists, which facilitates the automatic propagation of the changed data flow.[citation needed]react
git
Reactive programming has been proposed as a way to simplify the creation of interactive user interfaces and near-real-time system animation.[citation needed]github
For example, in a model–view–controller (MVC) architecture, reactive programming can facilitate changes in an underlying model that are reflected automatically in an associated view.[1]express
https://knockoutjs.com/documentation/observables.htmlthis
第一,定义 基础的 可观察对象:lua
var myViewModel = { personName: ko.observable('Bob'), personAge: ko.observable(123) };
第二, 定义存在依赖其余可观察对象的 计算对象spa
function AppViewModel() { // ... leave firstName and lastName unchanged ... this.fullName = ko.computed(function() { return this.firstName() + " " + this.lastName(); }, this); }
第3、绑定到视图prototype
The name is <span data-bind="text: fullName"></span>
若是基础的 可观察对象 改变, 则视图会自动跟着改变。code
https://github.com/fanqingsong/knockout-prototype
knockout模块实现, 包括 observale 和 computed 接口实现, 以及内部依赖管理实现。
let ko = {} ko.say = () => console.log("hello world") ko.dependency = (() => { let callerstack = [] let currentCaller return { currentCaller, callerstack } })(); ko.observable = (initVal) => { // for record caller, ie observer let observerCache = []; // store current observable value let currentVal = ""; if(initVal !== undefined){ console.log("initVal 0=", initVal) currentVal = initVal; } let observable = (newVal) => { // for read, subscribe to caller if( newVal === undefined ) { if (ko.dependency.currentCaller) { observerCache.push(ko.dependency.currentCaller) } return currentVal; // for write } else { currentVal = newVal; console.log("===",observerCache.length) for (const index in observerCache) { console.log("-----------3-", observerCache[index]); observerCache[index].callEvalWithDeps(); } } } return observable } ko.computed = (evalFunc) => { // store current observable value let currentVal = ""; let unValuated = true; let computedObservable = () => { if (unValuated){ computedObservable.callEvalWithDeps(); unValuated = false; } return currentVal; } computedObservable.callEvalWithDeps = () => { if (ko.dependency.currentCaller) { ko.dependency.callerstack.push(ko.dependency.currentCaller) } ko.dependency.currentCaller = computedObservable; currentVal = evalFunc(); let parent = ko.dependency.callerstack.pop(); ko.dependency.currentCaller = parent; } return computedObservable } module.exports = ko
调用
import ko from "./knockout.js" ko.say(); let aObservable = ko.observable("a"); console.log("aObservable=", aObservable()); let bComputed = ko.computed(() => { let result = aObservable() + "b"; console.log("result=", result); return result; }) // bind subscription to aObservable let bVal = bComputed(); console.log("bVal=", bVal); // trigger reactive effect aObservable("c"); console.log("bComputed=", bComputed())
运行
https://knockoutjs.com/documentation/computed-dependency-tracking.html
https://www.reactivemanifesto.org/