heluxjs/helux

[提示] 关于死循环检测

fantasticsoul opened this issue · 1 comments

3.5.5 开始草稿依赖收集功能默认支持,无需开启,并提供的强大的死循环检测功能,通过 alert 和 控制台输出方式帮用户地位死循环位置
image

关闭alert

不配置alertDeadCycleErr时,开发环境弹死循环提示,生产环境不弹,支持人工设置

const x = atomx({ a: 1, b: 2 }, { moduleName: 'yy', alertDeadCycleErr: false });

死循环案例

helux能检测以下几种常见的触发死循环情况,并主动阻止无限调用情况产生

watch 回调里修改自身依赖

const [state, , ctxp] = share(dictFactory, { moduleName: 'Case3' });

watch(() => {
  ctxp.reactive.f += 2;
}, () => [ctxp.reactive.f]);

watch(() => {
  setState(draft => { draft.f += 2 });
}, () => [ctxp.reactive.f]);

mutate fn、task回调里修改自身依赖

fn里 读取自己修改自己,触发死循环

const witness = mutate(finalPriceState)({
  fn: (draft) => {
    draft.time += 1;
  },
  desc: 'dangerousMutate',
});

task 里修改依赖列表里的值,触发死循环

const witness = mutate(finalPriceState)({
  deps: () => [priceState.a, finalPriceState.retA, finalPriceState.retB] as const,
  task: async ({ input: [a], setState, draft }) => {
    draft.retA += a; // 触发死循环
    setState(draft => { draft.retB += a }); // 触发死循环
  },
  desc: 'dangerousMutate',
  immediate: true,
});

多个函数间相互依赖形成死循环

多个 mutate 函数间的依赖闭环了形成相互依赖的局面,仅为导致死循环

// 发现a变化执行 changeB ---> 发现b变化执行 changeC  ---> 发现c变化执行 changeA ---> infinity loop
const [state] = atom(
  { a: 1, b: 0, c: 0 },
  {
    mutate: {
      changeB: (draft) => {
        draft.b = draft.a + 10;
      },
      changeC: (draft) => {
        draft.c = draft.b + 20;
      },
      changeA: (draft) => {
        draft.a = draft.c + 30;
      },
    },
  },
);

死循环存在漏洞
重现在https://github.com/zhangfisher/speed-form
的docs文档示例中,当开启时会一直提示存在死循环,但实际并没有