formily2.0探究 (二)

502 阅读6分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第10天,点击查看活动详情

这期实现formily/reactive的一些api的源码,主要讲observable、autorun、define 核心思想是参考mobx,但我感觉更像vue3

formily/reactive

api

observable

可观察对象

reaction

订阅者,接收tracker函数,类似effect,执行时,函数内部会对里面的可观察对象进行依赖收集,当前reaction会跟对象属性进行绑定,当属性进行写操作时,reaction会被触发

订阅到派发订阅是个循环,每次tracker都会收集依赖,依赖变动触发tracker执行

antorun

自动执行的响应器,类似上面,接收tracker函数,当属性进行写操作时,tracker会被触发

源码

observable

使用

import { observable, autorun } from '@/@formily/reactive' 
const values = {b:{c:d}}
const observableValues = observable(values)

observable.jsx

import { createObservable } from './internals';
import { MakeObservableSymbol } from './environment';
export function observable(target) {
  return createObservable(null, null, target);
}

internals.jsx

import { isNormalType, isFn } from './checkers';
import { RawProxy, ProxyRaw, MakeObservableSymbol } from './environment';
import { baseHandler } from './handlers';
export const createObservable = (target, key, value) => {
  //如果value不是对象,直接返回
  if (typeof value !== 'object') return value;
  const raw = ProxyRaw.get(value);
  //如果能找到对应的原生对象,说明此原生对象已经创建过代理对象了
  if (raw) {
    return value;//说明它本身就是一个代理对象,可以直接返回
  }
  //如果value是个普通的对象话就可以创建响应式对象
  if (isNormalType(value)) {
    return createNormalProxy(value);
  }
  return value;
}
const createNormalProxy = (target) => {
  // 创建代理对象
  const proxy = new Proxy(target, baseHandler);
  // 双向存map,{代理:对象},{对象:代理}
  ProxyRaw.set(proxy, target);
  RawProxy.set(target, proxy);
  return proxy;
}

handlers.jsx

import { isObservable } from './externals';
import { RawProxy } from './environment'
import { createObservable } from './internals';

export const baseHandler = {
  get(target, key) {
    const result = target[key];//Reflect.get(target,key);

    //如果此原生对象已经创建过代理对象了,直接返回
     
    const observableResult = RawProxy.get(result);
    if (observableResult) {
      return observableResult;
    }
    //如果这个结果不是一个可观察对象,就返回它对应的可观察对象
       //访问 {b:{c:d}} 的b,将{c:d}进行代理。深入代理
    if (!isObservable(result)) {
      return createObservable(target, key, result);
    }
    return result;
  },
  set(target, key, value) {
      // 如果修改值为对象,则给加代理
    const newValue = createObservable(target, key, value);
    target[key] = newValue;
   
    return true;
  }
}

environment.jsx

//普通对象=>代理对象
export const RawProxy = new WeakMap();
//代理对象=>普通对象
export const ProxyRaw = new WeakMap();

checkers.jsx

const toString = Object.prototype.toString;
export const isPlainObject = (val) => toString.call(val) === '[object Object]';
export const isNormalType = (target) => {
  return isPlainObject(target);
}

流程

判断值是否为对象,不是则返回原值

判断对象是否已经代理过,是的话返回其代理

若是普通对象,进行代理,用map存储 对象和代理的映射关系

get拦截中,如果拦截到属性结果的对象没代理过,给其代理上,也就是深入代理,set的时候也是

autorun

environment

// 全局正执行的tracker事件存放
export const ReactionStack = [];
// 属性 映射 tracker 
export const RawReactionsMap = new WeakMap();

autorun

类似vue3的effect

import { ReactionStack } from './environment';
export function autorun(tracker) {
  //reaction本质上是一个函数,当它观察到的对象和属性发生变化,此函数会重新执行
    //同vue3类似,将当前tracker存放全局变量,执行tracker
  const reaction = () => {
    ReactionStack.push(reaction);
    tracker();
    ReactionStack.pop();
  }
  reaction();
}

handlers

import { bindTargetKeyWithCurrentReaction, runReactionsFromTargetKey } from './reaction';
export const baseHandler = {
  get(target, key) {
      ...
    // 对象属性绑定 tracker
    bindTargetKeyWithCurrentReaction({ target, key });
...
  },
  set(target, key, value) {
    const newValue = createObservable(target, key, value);
    target[key] = newValue;
    // trigger,执行tracker更新数据
    runReactionsFromTargetKey({ target, key });
    return true;
  }
}

reaction

import { ReactionStack, RawReactionsMap } from './environment';
/**
 * 把某个对象的某个key和当前的reaction进行绑定
 * @param {*} operation {target,key}
 */
export const bindTargetKeyWithCurrentReaction = (operation) => {
  const { target, key } = operation;
  //最后一个Reaction就是currentReaction
  const currentReaction = ReactionStack[ReactionStack.length - 1];
  if (currentReaction) {
    addRawReactionsMap(target, key, currentReaction)
  }
}
//weakMap对象{ map对象:{ 属性:[tracker...] }}
const addRawReactionsMap = (target, key, reaction) => {
  //判断此target对象在RawReactionsMap里有没有值
  const reactionsMap = RawReactionsMap.get(target);
  if (reactionsMap) {
    const reactionSet = reactionsMap.get(key);
    if (reactionSet) {
      reactionSet.add(reaction);
    } else {
      let reactionSet = new Set();
      reactionSet.add(reaction);
      reactionsMap.set(key, reactionSet);
    }
    return reactionsMap;
  } else {
    //ArraySet 元素唯1的数组
    let reactionSet = new Set();//源码里作者自己封装了一个ArraySet
    reactionSet.add(reaction);
    const reactionsMap = new Map([[key, reactionSet]]);
    RawReactionsMap.set(target, reactionsMap);
    return reactionsMap;
  }
}
//weakMap对象{ map对象:{ 属性:[tracker...] }} 拿出tracker执行
export const runReactionsFromTargetKey = (operation) => {
  const { target, key } = operation;
  runReactions(target, key);
}
function runReactions(target, key) {
  const reactions = getReactionsFromTargetKey(target, key);
  for (let reaction of reactions) {
    reaction();
  }
}
const getReactionsFromTargetKey = (target, key) => {
  const reactionsMap = RawReactionsMap.get(target);
  if (reactionsMap) {
    return reactionsMap.get(key)
  } else {
    return new Set();
  }
}

流程

类似vue3

autorun(tracker)tracker是当函数内部可观察属性值变动时重新触发的函数

在可观察代理拦截getset,将tracker放全局,执行 tracker,触发访问可观察对象,触发get,在之中进行属性和tracker的绑定,当可观察对象属性值变化时,触发 set ,执行属性对应的tracker

define

指定具体属性的响应式行为

使用


define(form, {
  values: observable,
  fields: observable
});
目前支持的所有 Annotation 有:

observable/observable.deep 定义深度劫持响应式属性
observable.box 定义 get/set 容器
observable.computed 定义计算属性
observable.ref 定义引用劫持响应式属性
observable.shallow 定义浅劫持响应式属性,只代理一层
action/batch 定义批处理方法

现在来实现 observable

environment

弄个 symbol标识

export const MakeObservableSymbol = Symbol("MakeObservableSymbol");

observable

import * as annotations from "./annotations";
//observable.shallow = annotations.shallow;
// 等于下面的文件里的observable,返回函数,有个属性MakeObservableSymbol,赋值maker,两个symbol
observable[MakeObservableSymbol] = annotations.observable;

annotations/observable


import { createAnnotation, createObservable } from '../internals';
import { bindTargetKeyWithCurrentReaction, runReactionsFromTargetKey } from '../reaction';
// 返回函数,有个属性MakeObservableSymbol,赋值maker
export const observable = createAnnotation(
    //maker  将对象转化成代理并劫持
  ({ target, key, value }) => {
    //先把target对象的key属性变成可观察对象并存在store.value属性上
    const store = {
      value: createObservable(target, key, target[key])
    }
    function get() {
      bindTargetKeyWithCurrentReaction({ target, key });
      return store.value;
    }
    function set(value) {
      value = createObservable(target, key, value);
      store.value = value;
      runReactionsFromTargetKey({ target, key });
    }
    Object.defineProperty(target, key, {
      get, set, enumerable: true, configurable: false
    });
    return store.value;
  }
);

model(入口)


import { isObservable, isAnnotation } from './externals';
import { getObservableMaker } from './internals';
export function define(target, annotations) {
    //如果是代理对象了,返回
  if (isObservable(target)) {
    return target;
  }
    //{value:observable,fields: observable}
  for (const key in annotations) {
      // annotation:observable
    const annotation = annotations[key];
    //如果annotation是一个合法的注解的话才会进入 如observable
    if (isAnnotation(annotation)) {
        // 获取maker 将对象转化成代理并劫持 ok
      getObservableMaker(annotation)({ target, key });
    }
  }
}

internals

export const isAnnotation = (target) => {
  return target && target[MakeObservableSymbol];
}
// 返回函数,有个属性MakeObservableSymbol,赋值maker
export const createAnnotation = (maker) => {
  const annotation = () => {};
  if (isFn(maker)) {
    annotation[MakeObservableSymbol] = maker;
  }
  return annotation;
};
// 如果是observable,拿到maker要两层
export const getObservableMaker = (target) => {
  if (target[MakeObservableSymbol]) {
    if (!target[MakeObservableSymbol][MakeObservableSymbol]) {
      return target[MakeObservableSymbol];
    }
    return target[MakeObservableSymbol][MakeObservableSymbol];
  }
  //return annotation[MakeObservableSymbol];
};

流程

define(form, { values: observable, });

在之中,observable是注解,

定义observable[MakeObservableSymbol] = annotations.observable;,只要判断注解是否存在 MakeObservableSymbol就可以知道注解是否正确了

annotations.observable是一个函数,参数是maker函数(可以让对象转化为可观察对象),最终返回一个函数,这个函数的 MakeObservableSymbol赋值为maker。

define时,先检测属性的注解observable是否正确,也就是检测observable[MakeObservableSymbol]是否存在,正确则,获取其maker函数,将该属性转化为 可观察对象。

observable.shallow

github1s.com/alibaba/for…

简单讲就是多了个和RawProxy一样的 RawShallowProxy,当对shallow对象进行观察时,将其 对象和代理存进去。

baseHandlers不变,当访问对象里的属性,值是对象时,会进行 createObservable

此时shallow对象会在RawShallowProxy其中找到,直接返回,不继续代理了。

# observable.jsx
observable.shallow = annotations.shallow
# annotations/shallow.jsx
// createObservable多了个true
export const shallow = createAnnotation( ({ target, key, value }) => 
{ const store = { value: createObservable(target, key, target[key], true), 
}
# reactive\internals
export const createObservable = (target, key, value, shallow) => {
    。。。
    //拦截二层代理
if (target) {
    const parentRaw = ProxyRaw.get(target) || target
    const isShallowParent = RawShallowProxy.get(parentRaw)
    if (isShallowParent) return value
  }
if (shallow) return createNormalProxy(target, true)
}   
const createNormalProxy = (target: any, shallow?: boolean) => {
  const proxy = new Proxy(target, baseHandlers)
  ProxyRaw.set(proxy, target)
  if (shallow) {
    RawShallowProxy.set(target, proxy)
  } else {
    RawProxy.set(target, proxy)
  }
  return proxy
}