V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
FaiChou
V2EX  ›  程序员

redux-saga 中 channel 的原理是怎样的?

  •  
  •   FaiChou ·
    FaiChou · 2021-12-14 12:02:36 +08:00 · 918 次点击
    这是一个创建于 1075 天前的主题,其中的信息可能已经有所发展或是发生改变。

    摊牌了, 源码没看懂. 有个地方想请教, 例子:

    function* watchAndDo() {
      const channel = yield actionChannel('TEST');
      while (true) {
        const payload = yield take(channel);
        yield call(Api, payload);
      }
    }
    

    这个例子中, 假如一起来了 10 个 TEST, 则会一个一个执行. 那么这里 channel 是如何做到等待循环里的 block 结束再派发下一个动作的?

    目前了解到: 创建 channel 后, dispatch 的消息会加入到 buffer 中, buffer 是一个数组.

    FaiChou
        1
    FaiChou  
    OP
       2021-12-14 16:29:18 +08:00
    明白了:
    FaiChou
        2
    FaiChou  
    OP
       2021-12-14 16:36:08 +08:00
    function take(cb) {
    if (closed && buffer.isEmpty()) {
    cb(END)
    } else if (!buffer.isEmpty()) {
    cb(buffer.take())
    } else {
    takers.push(cb)
    cb.cancel = () => remove(takers, cb)
    }
    }

    上面是 channel.js 里的代码, 首先 dispatch() 或者 put() 会将消息放到 buffer 中, 当 buffer 为空, 则还没有任何消息到来, 这时候 take(channel) 或者 take('MESSAGE') 会存到 takers 中, 在下次消息到的时候, 取出来一个来执行:

    function put(input) {
    if (closed) {
    return
    }
    if (!takers.length) {
    return buffer.put(input)
    }
    const cb = takers[0]
    takers.splice(0, 1)
    cb(input)
    }

    如果阻塞时候 buffer 来了很多消息, 后来阻塞结束(比如例子中 while 的新一轮循环), 判断 `!buffer.isEmpty()` 会直接从 buffer 中取出一条消息来执行 cb(buffer.take())
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2835 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 08:43 · PVG 16:43 · LAX 00:43 · JFK 03:43
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.