例子 你用过RxJS吗? 其中最重要的概念就是Observable 和 Observer。
Observable 决定了values如何传递给Observer,Observer本质上就是一些callback的集合。
来看看如下代码。
const observer = {
next: (value) => {
console.log('we got a value', value)
},
error: (error) => {
console.log('we got an error', error)
},
complete: () => {
console.log('ok, no more values')
}
}
上面就是一个Observer,很明显就是3个callback而已。
接下来我们可以把让这个Observer订阅一个Observable,Observable 会传递给这个Observer以值(value)或者error。
const observable = new Observable((subscriber)=> {
subscriber.next(1)
subscriber.next(2)
setTimeout(() => {
subscriber.next(3)
subscriber.next(4)
subscriber.complete()
}, 100)
})
上面的代码是在说,当一个subscriber订阅的时候:
- 首先得到值
1
- 然后得到值
2
- 等待100 ms
- 得到值
3
- 得到值
4
- 没有更多的值了,结束。
如果我们现在把上面的observer
订阅给上述observable
的话,next
和 complete
会被顺序调用。(注意到 2 和 3之间有些delay)
const sub = observable.subscribe(subscriber)
// we got a value 1
// we got a value 2
// we got a value 3
// we got a value 4
// ok, no more values
注意subscribe()
返回的是一个Subscription ,这个subscription可以用来取消订阅。
const sub = observable.subscribe(subscriber)
setTimeout(() => {
// ok we only subscribe for 100ms
sub.unsubscribe()
}, 100)
以上就是基本的Observable 和 Observer,后续会有更多有意思的题目,但是该题目就到这里了。
请你实现一个基本的Observable,使得上述描述的内容成为可能。
一些额外的要求列在了这里
error
和complete
只能触发一次。其后的next/error/complete
需要被忽略。- 在订阅的时候
next/error/complete
需要都不是必须。如果传入的是一个函数,这个函数需要被默认为next
。 - 需要支持多个订阅。
更多阅读
实现 脑子转过来后也不是很难,就是对subscriber的next等方法进行判断一下就行了。
class Observable {
constructor(setup) {
this._setup = setup;
}
subscribe(subscriber) {
const _subscriber = {
unSubscriber: false,
next: function (value) {
if (this.unSubscriber) return;
if(typeof subscriber == 'function') return subscriber(value)
return subscriber.next ? subscriber.next(value) : null
},
error: function (error) {
if (this.unSubscriber) return;
this.unsubscribe();
return subscriber.error ? subscriber.error(error) : null
},
complete: function () {
if (this.unSubscriber) return;
this.unsubscribe();
return subscriber.complete ? subscriber.complete() : null
},
unsubscribe: function () {
this.unSubscriber = true;
}
}
this._setup(_subscriber);
return _subscriber;
}
}