数据的生产者/消费者与推拉模式(Push/Pull)
将数据看作是商品, 生产数据的是生产者, 使用数据的是消费者.
生产者有很多, Function / Promise / Generator / Iterator / RxJS. 等等.
但这些生产者的类型却不一样, 它们被分为 Push(推模式) 和 Pull(拉模式).
拉模式的生产者更加常见, 比如: Function, Iterator 等.
如何区分推和拉.
对于拉模式来说, 何时生成数据是由消费者决定的, 比如 function, 是在用的时候产生数据. 你不用, 它就不产生.
对于推模式来说, 何时生成数据是由生产者决定的, 比如 Promise, 我自己把数据拿到, 然后将状态固定(resolved), 你什么时候要用, 就 .then 获取即可.
也就是说. 推模式更加适合"异步请求"或"事件". 因为这两种情况下, 数据的产生并不受消费者调用而直接获取的. 它们的产生是由请求成功 / 事件触发这些情况决定的.
从表现来看, 推模式在代码中常常表现为"链式调用", 比如: Fetch(url).then()
, 而拉模式则是同步立即获取, 比如: Date.now()
惰性执行与主动执行
所谓惰性执行, 指的是某段代码, 自他声明以后, 需要调用才会执行. 主动执行则相反, 会在声明后立刻执行.
前者的典型代表是 Function, 此外 Generator 和 Iterator 也是, RxJS 也是, 但它不是调用后执行, 而是订阅后执行.
后者(主动执行)的典型代表是 Promise, 它会将执行的结果保存好, 状态固定, 后续无论调用多少次都是一样的值, 因为它已经计算完了. 不受外界影响.
let count = 1
function getCount() {
return new Promise(resolve => {
count++
resolve(count)
})
}
const promise = getCount()
promise.then(console.log) // 2
promise.then(console.log) // 2
promise.then(console.log) // 2
promise.then(console.log) // 2
订阅一个 Observable 就像调用一个函数
由于 RxJS 也是惰性执行的, 它跟函数是非常类似的. 也因此, RxJS 是一种纯函数编程的库. 下面例子中函数调用使用 .call, Observable 调用使用 .subscribe, 两者其实是类似的. 只是 函数调用是 拉模式, Observable 是推模式.
// 1. 函数调用
function foo() {
console.log('Hello, World!')
return 42
}
console.log(foo.call())
// Hello, World!
// 42
// ----------------------------------------
// 2. RxJS Observable
import { Observable } from 'rxjs'
const observable = new Observable(subscriber => {
console.log('Hello, World!')
subscriber.next(42)
})
observable.subscribe(console.log)
// Hello, World!
// 42