剑客
关注科技互联网

公司的秋季技术交流会留的一些感想

公司内部的活动, 所以去的还是内部的前端比较多, 拉外边的牛人来讲.

除了经常打招呼的贺老跟民工叔叔, 还来了起点中文的同学, 不过名字没认全,

然后见到了 ningjs 的李寅侃大大, 当时看了视频, 确实聊着就哈哈哈哈 😀

看起来以后有技术大会找人做总结应该是经常发生的事情了.. 很有意思.

聊到两块我关注比较多的话题, 我觉得可以留点笔记下来.

Rx

我对 CSP 的理解, 以及 Rx 的区别

对我来说 CSP 方案应该是处理时间相关的任务通信的很重要的办法,

因为对 Clojure 社区有紧密关系, 而且跟 Go 社区也有接触,

我个人认为 CSP 是足够清晰明确的一个方案, 而且也更容易上手,

之前文章也安利过. 感觉最近遇到的一个例子看上去比较清晰,

文章以识别一段组合键 "abbaba" 为例子, 对比两个方案:

https://www.jayway.com/2014/0…

作者认为 CSP 更清晰, 这也是我的观点, 毕竟是站在 CSP 的角度看的,

这里用的是 ClojureScript 代码, 用了 core.async 的实现:

(go
  (loop [correct-clicks []
         timeout (async/timeout combination-max-time)]
    (let [[val channel] (alts! [a b timeout])
          clicks (conj correct-clicks val)]
      (cond
        (= channel timeout)
          (do (set-html! "You're not fast enough, try again!")
              (recur [] (async/timeout combination-max-time)))
              
        (= clicks secret-combination)
          (do (set-html! "Combination unlocked!")
              (recur [] (async/timeout combination-max-time)))
              
        (and (= val (first secret-combination)) (zero? (count correct-clicks)))
          (do (set-html! clicks)
              (recur clicks (async/timeout combination-max-time)))
              
        (= val (nth secret-combination (count correct-clicks)))
          (do (set-html! clicks)
              (recur clicks timeout))
              
        :else
          (do (set-html! clicks)
              (recur [] timeout))))))

go 是个 Macro, 主体的代码要看 loop 里边,

首先 loop 有两个循环的参数 correct-clicks timeout , 默认参数是空向量 [] 和默认的 timeout Channel.

后边的代码, 调用的 recur 的地方会对 loop 调用进行尾递归,

也就是用 recur 的参数, 作为新的循环变量, 继续执行中间的代码,

整个代码应该分成两部分看, 一部分是处理了跟时间相关的行为, 一部分处理了逻辑.

首先是时间, 整个代码从 cond 判断出来, 所有分支到是走到 recur 的,

说明整个就是彻底的循环, 在整个程序的生命周期监听这事件,

代码是同步的, 但是由于 go 的作用, 实际上执行当中会进行等待,

(alts! a b timeout) 是从 3 个 Channel 等待任意的数据,

aA 这个键的事件的 Channel, b 类似, timeout 就是超时的 Channel.

所以每个循环都会回到这里, 等待下一个事件, 然后继续执行代码.

逻辑部分, cond 判断了行为之后, 会生成 clicks 这个向量,

可以看到一些规则, 比如 timeout 了, 就清空 clicks ,

比如 clicks 与目标序列一致, 就打印出成功解锁, 以及下面还有几条复杂的逻辑,

而这些逻辑实际上就是对数组中的元素进行判断, 能弄懂算法就直接能写,

这部分代码和异步或者时间其实毫无关系, 没有类库就能直接写出来.

所以 CSP 的方案将时间因素处理之后, 实际上就简化为数组处理的问题了,

而在 ClojureScript 也就自然而然是尾递归进行循环就能计算的,

在 Go 当中, 推想就是 for 循环的结构, 进行类似的判断, 而且写法更直白.

这就是 CSP 的思路了, 转化事件流为普通的控制流问题, 再老办法解决.

与之对应的是 RxJS 的代码, 某种程度上来说比 js 更好懂,

var evaluationStream = bothButtons
  .merge(
      bothButtons
      .throttle(5000)
      .map(function(){return "reset";})
      ) // (2) and (3)
  .scan(function(acc, x) { // (1)
            if (x === "reset") return "";
            return acc + x;
        })
  .map(function(newAcc) {
            if (newAcc.length > secretCombination.length) {
                return newAcc.substr(newAcc.length - secretCombination.length);
            } else {
                return newAcc;
            }
       })
   .do(function(combination) {
                card.html(combination);
       })
  .map(function(combination) {
            return combination === secretCombination;
       });

我个人对 Rx 熟悉有限, 无法深入讲, 只能看明白大致表达的意思,

超过 5s 发出 reset 事件, 然后重置, 否则记录序列, 最后匹配等等,

不过这种中间并不简单, 据说有 edge case 没处理好,

而且解决 edge case 的过程慢复杂的, 可以看这个 issue 当中的记录, 总之有点难懂.

https://github.com/Reactive-E…

那这是我理解的 CSP 和 Rx 在解决类似问题上的主要的区别,

在函数式编程当中, 关注的是 state 和 function 两个角度,

state 其实就是 data, 不过可能还是 data + mutation, 也就是变化的数据,

从这个角度, CSP 把 state 保存在了函数参数当中, 进行复制和传递,

而 Rx 将 state 在数据流的处理方法的结构当中进行保存修改和传递,

差别在于, CSP 处理数据时, 是明确将数据取出, 然后循环处理的,

而 Rx 将数据的操作封装为函数, 然后通过 Rx 的 operator 方法传毒函数,

可以回顾一下两个例子, 是不是有这个区别?

teambition 的例子

回到叔叔的演讲上来, teambition 面对的问题主要是数据同步,

具体演讲当中的阐述很清晰, 我只能画画图, 但叔叔把很多细节讲明白,

等有机会看 slide, 还有等叔叔有时间发文章…

其中数据的展开和更新的问题, 需要足够强大的抽象才行,

而且当情况复杂之后, 数据流的调试也就需要更好的方案, 比如 cyclejs 作者已经有一个:

https://github.com/cyclejs/cy…

公司的秋季技术交流会留的一些感想

叔叔也正在做一个, 讲这个数据流更好地呈现出来, 还刚开始做:

https://github.com/xufei/rxjs…

Rx 是用于 Reactive Programming 的一个库, 借鉴了一些 Functional 的手法,

抽象方式很强大. 而数据的同步, 实际上确实是个一响应式的数据变化的过程,

首先数据在顶层层出, 一个形态, 等数据逐渐分发的 Components 当中, 又是新的形态,

所以中间数据形态的转化和界面的更新, 其实复合 Reactive 的 pattern.

之前也说到过, 总之两个方案是非常近似的.

不过我有一些思考, Rx 会不会过于强大, 强大到多余,

比如 Vue 就是 Reactive 分发数据的例子, 不需要 Rx 的强大, 也能完成数据分发,

React 方面的方案也类似, 即便脱离一些强大的概念, 也能完成任务,

挺演讲结束, 我想到一个 edge case, 就是说 Rx 真的强大过头,

比如说, 从 React 的演讲来看, Model View 的关系, f(model) = view-dsl ,

意味着 Model 任意改变, View 都是限定的, 理论上有这种对应,

但是 Rx 当中存在可能性, 比如流的处理当中可以插入状态以及副作用,

我的意思是, Rx 来分发数据, 是有办法做到改变 Model 的顺序和时间, 导致 View 结果多样化的,

所以这个在流当中存在的状态信息, 对于生成界面来说, 是多余的.

我由此推导的一个结论是, Rx 用在数据分发上, 功能过于强大了.

当然也有好处, 有些异步的情况通过 Rx 能比较轻松解决,

不过站在 FP 的角度上说, 引入了额外的依赖, 总归担心出现意外,

我倒是不觉得用了会有问题, 就是要明白这中间是有可能制造出不想要的行为来的.

打包方案

然后是提问环节, 有人问贺老当初挖的坑怎么怎么, 我本来没听明白, 后来有人给了链接:

http://www.zhihu.com/question…

大致就是打包的问题, 原来以为 HTTP2 流行, 结果大量的打包工具会下岗,

现在看来到预言的时间 webpack 之类应该会活得好好的, 至少现在 2 正常开发着…

于是从打包问题衍生出来好多话题, 比如有想法了就缺程序员去做了,

比如专门整合前端代码的打包发布技术, 为其他公司提供服务等等.

不大情况细节, 但是 HTTP2 如果真的普及, 想想真的是可能造成洗牌之类的事情,

中间也提到, 代码打包不大可能做到页面完全配合缓存按需加载的那种细粒度,

而只有每个文件单独存放, 才有可能做到, 而这技术完全依赖 HTTP2 才能保证性能.

所以这个事情大概就是按着依赖关系卡在这儿了.

我追着 PWA 技术更新的时候, 也感到安路由打包是个相当棘手的问题,

因为涉及到代码的自动分包和动态加载, 对编译工具的要求其实蛮高的,

开源社区的工具我估计也就 Webpack 能自带全部需要的功能, 其他方案要靠拼凑,

当然即便带了功能, 要做好依然不简单, 包括路由, 服务端, 都要做类似的配合.

所以按路由打包拆分是个挺棘手的话题, 至于前面讨论的更强大的方案… 更遥远..

结尾

今天交流下来还是很有收获的, 还增长了见识, 虽然问题依然不明朗, 但是找到不少的参照,

这些问题说起来依然是老问题, 当初我进 teambition 时候就跟寸志他们在头疼了,

然而当时没有刚挖 React Angular, 只有 RequireJS, 能做的其实不多,

现在的生态已经出现了大量的工具链, 但工程化的各个缝隙依然需要填补, 真麻烦.

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址