farrow-js / farrow

A Type-Friendly Web Framework for Node.js
https://www.farrowjs.com
MIT License
768 stars 37 forks source link

请教 hook 相关的问题 #40

Closed uinz closed 3 years ago

uinz commented 3 years ago

如果不利用 async_hook 是不是就很难实现当前 hook 的效果?

总觉得 async_hook 实现有些黑魔法

那么在不提供 async_hook 环境里, 要如何实现 react hook like 且 Promise 友好这套 farrow hook 的机制呢?

其实我是想知道 这套设计的背后还有哪些知识点

蟹蟹

Lucifier129 commented 3 years ago

这是一个取舍和权衡的结果,本质上是在模拟 Algebraic Effects and Handlers 的一个基本应用——Dependent Injection。

react-hooksvue-composition-api 实现的是 sync function hooks,基本思路是在 call function 前,把 currentDispatchercontext container 切换成当前需要的,called function 之后,再重置回 prev 那个。

可以理解为一种局部的 context switchinguseState, useReducer 内部共享的一个闭包变量,在调用过程中,不断切换。

基本思路演示如下:


let currentDispatcher = null

let useState = (init) => {
  return currentDispatcher.useState(init)
}

let useReducer = (reducer, init) => {
  return currentDispatcher.useReducer(reducer, init)
}

let withImpl = (f, impl) => {
   let prev = currentDispatcher
  try {
    currentDispatcher = impl
   return f()
  } finally {
    currentDispatcher = prev
  }
}

let test = () => {
  let [state, setState] = useState(0)
  let [state0, dispatch] = useReducer(() => {}, 0)
}

// useState 的 offset/index 递进实现略……
let result = withImpl(() => test(props), {
  useState: init => {
    return [init, () => {}]
  },
  useReducer: (reducer, init) => {
    return [init, () => {}]
  }
})

可以理解为 interface/implements 是在 call-site 里实现,而非 definition 在定义阶段去 implements,并且这个 call-site 是跨 caller 的。也就是说,它像事件冒泡,去向上一个 caller 不断传递,直到找到一个 handlers/implements。这是我们能够编写 custom-hooks 的原因所在,它是跨 caller 的,不管封装多少层函数调用,hooks 访问的都是 withHandlers 所在的层次。

如上,withImpl 是同步的 try-finally 切换,一旦 f() 是异步,整个机制就不成立了。

为了支持异步,我们发现:

这类 hooks 实践,只是 Algebraic Effects and Handlers 的极为小的、极为基础的应用,已然能够给我们带来很大的便利。未来可以挖掘更多应用场景,提升开发体验。

关于 Algebraic Effects and Handlers 实战的更多内容,可以访问 koka-lang 的 Effect Handlers 部分,直接感受 first-class 的语言特性,比通过模拟的方式实现的,更加清晰一些。

如果能完整学习和实践一下 koka 语言更佳。

Lucifier129 commented 3 years ago

async_hooks 里的黑魔法气息,可能来源于它相比 Algebraic-Effects 而言,有点 ad hoc

通过 Algebraic-Effects,我们可以将 async/await 从带语法的语言特性,降级为 library。异步处理是 Algebraic-Effects 的其中一个应用。

如果我们看到了通用特性,我们了解到 async_hooks 是一种模拟和补充,我们可以从 Algebraic-Effects 视角感受到统一,可以更容易接受 async_hooks 的某些用法。

不管底层如何 ad-hoc,如何 dirty,只要我们封装的抽象,满足某些理论上更干净和一致的特性要求即可。

safe/clean abstraction based on unsafe/dirty layer

uinz commented 3 years ago

十分感谢, 非常好的解决了我的疑惑. 🤙🏻