callbag,一个有趣的规范

push 和 pull 模型

如果你了解 RxJs,在响应式编程中,Observable 和 Obsever 是 push 模型,与之对应的,还有一个 pull 模型:

  • Pull(f(): B:返回一个值。
  • Push(f(x: A): void:响应式的,当有值产生时,会发出一个事件,并携带上这个值。订阅了该事件的观察者(Observer)将获得反馈。

JavaScript 中的 Math.random()window.outerHeight 等都是 pull 模型:

const height = window.outerHeight();
// 或者是迭代器写法
function* getWindowHeight() {
while(true) {
yield window.outerHeight;
}
}
var iter = getWindowHeight()
iter.next()

pull 模型包含两个部分:

  • 生产者 :负责生产数据,是数据源
  • 消费者 :负责消费数据,是数据的使用方

在 pull 模型中,数据是 按需索取 的。

再通过 RxJs 看一个 push 模型的例子:

Rx.Observable
.fromEvent(document, 'click')
.map(event => `Event time: ${event.timeStamp}`)
.subscribe(function observer(val) {
console.log(val);
})

push 模型的组成包含了两个部分:

  • 可观察(可监听)对象 :是数据来源
  • 观察者(监听者):是数据的使用方

与 pull 模型不同,观察者 不能主动索取数据 ,而是观察数据源,当数据源有数据时,才可消费和使用。

push 模型有这么一些优点:

  • 高度复用的可观察对象 :通过对源可观察对象使用不同的运算子,可构建出新的可观察对象。
  • 延迟执行 :可观察对象只有被观察者订阅,才会派发数据。
  • 声明式、描述未来的代码 :我们只用声明数据源和数据消费方式,而不用关心数据交付时的细节。

Cycle.js 的作者 Andre Staltz 长久以来面对一个问题,Cycle.js 及其推荐使用的响应式编程库 xstream 都是 push 模型的,这让框架的模型和业务代码都受益于 push 模型的优点。但是,实际项目中,我们还是有不少 pull 模型下的需求,Andre Staltz 也开了一个 issue ,讨论如何更好的使用代码描述 pull 模型。

2017.03 - 2017.08 的学习总结

从今年三月份开始,我在前端的学习路径是:

  1. JavaScript 函数式编程(Lisp、Haskell 开发者轻喷)
  2. 函数响应式编程:FRP,这一块主要是以学习 Rxjs 为主
  3. 函数式编程和函数响应式编程的应用:这一块主要是以学习 Cycle.js 为主

斯坦福机器学习笔记

系列文章已发布至 Gitbook

本书为斯坦福吴恩达教授的在 coursera 上的 机器学习公开课 的知识笔记,涵盖了大部分课上涉及到的知识点和内容,因为篇幅有限,部分公式的推导没有记录在案,但推荐大家还是在草稿本上演算一遍,加深印象,知其然还要知其所以然。

本书涉及到的程序代码均放在了我个人的 github 上,采用了 python 实现,大部分代码都是相关学习算法的完整实现和测试。我没有放这门课程的 homework 代码,原因是 homework 布置的编程作业是填空式的作业,而完整实现一个算法虽然历经更多坎坷,但更有助于检验自己对算法理解和掌握程度。



一步步写一个 co

文章已发布至 GitBook

现在,我们有三个 markdown 文件 file1.md,file2.md,file3.md,我们想要统计这三个文件的大小信息,并输出为以下格式:

{file1: 5384, file2: 2712, file3: 13942}

underscore 源码分析

文章已发布至 GitBook

写作意图

起初,我分析 underscore 的源码只是想更深入的了解 函数式编程(Functional Programming),但分析结束后,我就觉得单纯的源码注释不足以记录我的收获、理解和感悟,所以我想把这些写下来,我粗略地将写作意图概括如下:

  • 函数式编程近些年非常火爆,诸如 haskwell 这样的纯函数式编程语言获得了非常高的社区活跃度。JavaScript 支持多范式编程,抛开 underscore 和 lodash 这样的生来为了函数编程的库不谈,诸如 redux 这样的库也大量运用了函数式编程,即便作为一个 react+redux 的业务开发者,想要深入理解的 redux 的实现机制,也不得不学习函数式编程。因此,学习函数式编程,将会成为 JavaScript 开发者的必须。

    在阅读 underscore 的源码期间,被作者 jashkenas(他同时也是 backbone 和 coffee 的作者)的功力深深折服,一些功能可能我也能写出,但绝对写不了如此健壮。所以,深入学习 underscore 源码,不仅有助于我们认识函数式编程,也能深化我们对于 JavaScript 中一些基础知识的理解和掌握。

    随着 backbone 的衰落和 lodash 的崛起,underscore 的热度已经不及当年,但是截止这篇文章的开始前的一个月,underscore 仍然有最新的 bug 修复,可见作者 jashkenas 仍然没有放弃 underscore 的维护。所以现在分析 underscore 的源码仍然不显得过时。相较于 lodash,underscore 的源码更加短小,也不太涉及 JavaScript 中的一些奇淫巧技,所以,分析 underscore 更加适合 JavaScript 开发者的进阶。在完成了 underscore 的源码分析后,希望我自己有时间,也希望读者有意愿再去分析 lodash 的源码,后者在性能和功能上都已经超越了 underscore,并且长时间霸占了 npm 了最热 package 的位置。

thunkify

引子

自己之前曾经撸过一个验证库,代码大致如下:

function validate(data, rules, cb) {
// ....
// 一切完成后会触发回调函数
cb(null, errMap);
}

出于性能上的考虑,该库被封装为了一个异步函数,需要提供一个回调函数 cb 来获得验证结果,该回调函数是一个满足 node 规范的 error-first callback。在其他系统中,该库使用良好,但是,新项目使用了 koa,我在中间件中使用这个库提供的 validate 方法, 却连编译期都没有通过:

使用 ES6 中的 generator 来优化异步过程

原文:Going Async With ES6 Generators 本文在作者文章的基础上,适当补充了一些代码及说明

ES6 中的 generator 能够帮助我们提供一种类似同步一样的代码风格,来将异步过程的具体实现隐藏。这样的好处就是我们能够更加自然的表达自己的业务流程(work flow),而避免陷入异步的麻烦中。换言之,借助于 generator,我们既拥有了异步执行的能力,又不用再绞尽脑汁的去维护异步代码。

继续阅读本文,你会发现这么做的结果简直太美妙了,以前那些糟糕的异步代码现在讲会向同步代码那样变得 易于阅读 可维护 。需要知道的是,这个同步只是代码风格上的同步,他的执行过程仍然是异步的。

说了那么多,仍然有些抽象,现在我们由浅入深地看看到底怎么通过 ES6 来优化异步过程。

JavaScript 中的递归优化

引子

说到递归,我们先来看一个最常见的递归用例: 计算阶乘

function factorial(n) {
if(n==1) return 1;
return n*factorial(n-1);
}

测试一下:

factorial(5); // => 120

似乎一切正常,5 的阶乘 120 被正确计算出来了,我们试着把数字调大一些:

factorial(70000);
// Uncaught RangeError:Maximum call stack size exceeded(…)

浏览器提示我们 栈溢出 了(测试环境:chrome 51),究竟发生了什么呢?

Redux 中间件的实现

引子

我们知道在 Redux 中,dispatch 的作用在于派发一个 action,该 action 会被 reducer 收到,reducer 根据 action 的类型进行相应的状态(state)维护: