RxJS的另外四種實現方式(二)——代碼最小的庫(續) 頂 原

接上篇 RxJS的另外四種實現方式(一)——代碼最小的庫

上篇我們展示了生產者interval和操作符filter的實現,接下來我們看一下消費者subscriber的實現

callbag的實現

const subscribe = (listener = {}) => source => {
  if (typeof listener === "function") {
    listener = { next: listener };
  }

  let { next, error, complete } = listener;
  let talkback;

  source(0, (t, d) => {
    if (t === 0) {
      talkback = d;
    }
    if (t === 1 && next) next(d);
    if (t === 1 || t === 0) talkback(1);  // Pull
    if (t === 2 && !d && complete) complete();
    if (t === 2 && !!d && error) error( d );
  });

  const dispose = () => {
    if (talkback) talkback(2);
  }

  return dispose;
}

module.exports = subscribe;

最小庫的實現

exports.subscribe = (n, e, c) => source => source(n, err => err ? e && e(err) : c && c())

我們可以看到,如果讓讀者自行擴展其他操作符或者生產者都是十分容易的。相反如果要寫出正確的callbag的話,就十分考驗技術了。

大家可以自行驗證兩個庫的運行情況是否正確:

//pipe語法
interval(1000) |> filter(x => x > 4) |> subscribe(console.log)
//使用pipe函數代替
pipe(interval(1000),filter(x => x > 4) ,subscribe(console.log))

最後再展示一個skip操作符的實現源碼

exports.skip = count => source => (n, c) => {
    let _count = count;
    let _n = () => (--_count === 0 && (_n = n));
    return source(d => _n(d), c)
}

最小庫實現技術手段

與callbag相似,最小庫使用高階函數來代替傳統的observable、observer等對象,所以不需要核心庫(基類)。傳統方式在創建observable的時候傳入observer對象,作爲代替方案,是向observable高階函數傳入next和complete回調函數作爲訂閱行爲。next和complete回調函數合起來可以看成是observer對象。而observer分成了next和complete回調函數的好處是,可以進行分開傳遞,有時候就可以直接透傳,如上文的skip函數中的complete回調函數c,直接透傳到源observable裏面。訂閱行爲即調用observable函數返回值被利用來作爲dispose行爲,很多時候就會隱含的進行傳遞如上面的skip操作符。js的許多語法可以使得代碼更加短小精悍,例如:

  • 箭頭函數爲表達式的時候,無需寫大括號,以及return
  • js的逗號表達式,可以返回表達式最後一個逗號後面的值
  • js的邏輯運算符&&、||可以用來代替if語句等
  • js的函數變量可以替換成新的函數,使得行爲發生變化

當然這個庫最核心的就是函數閉包,本質上來說,定義函數就相當於定義了一個類,閉包裏面的變量都是這個函數調用後的僞對象的屬性,這導致了,雖然代碼已經極端短小,但性能卻不是最高的原因。下一篇我將介紹最高性能的庫的實現方法。

(未完待續)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章