jiayisheji / blog

没事写写文章,喜欢的话请点star,想订阅点watch,千万别fork!

Home Page:https://jiayisheji.github.io/blog/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

RxJS学习笔记

jiayisheji opened this issue · comments

commented

RxJS

Observable是Rxjs核心

Observable

Observable关联2个设计模式: 观察者模式(Observer Pattern)和迭代器模式(Iterator Pattern)。

观察者模式(Observer Pattern)和迭代器模式(Iterator Pattern)

观察者模式(Observer Pattern)

一句话描述:观察者模式是如何在(事件(event)跟监听者(listener)或者发布者(Publisher)跟订阅者(Subscriber))的互动中做到去解耦。也叫发布订阅模式

实现一个观察者模式

function Producer() {

    // 这个 if 只是避免使用者不小心把 Producer 当作函式来调用
    if(!(this instanceof Producer)) {
      throw new Error('请用 new Producer()!');
      // 仿 ES6 行为: throw new Error('Class constructor Producer cannot be invoked without 'new'')
    }

    this.listeners = [];
}

// 加入监听的方法
Producer.prototype.addListener = function(listener) {
    if(typeof listener === 'function') {
        this.listeners.push(listener)
    } else {
        throw new Error('listener 必须是 function')
    }
}

// 移除监听的方法
Producer.prototype.removeListener = function(listener) {
    this.listeners.splice(this.listeners.indexOf(listener), 1)
}

// 发送通知的方法
Producer.prototype.notify = function(message) {
    this.listeners.forEach(listener => {
        listener(message);
    })
}

var egghead = new Producer(); 
// new 出一个 Producer 实例叫 egghead

function listener1(message) {
    console.log(message + 'from listener1');
}

function listener2(message) {
    console.log(message + 'from listener2');
}

egghead.addListener(listener1); // 注册监听
egghead.addListener(listener2);

egghead.notify('A new course!!') // 当某件事情方法时,执行

迭代器模式(Iterator Pattern)

一句话描述:Iterator是一个迭代器,它的就像是一个指针(pointer),指向一个数据结构并产生一个数组,这个数组会保存数据结构中的所有元素。

实现一个迭代器模式

function IteratorFromArray(arr) {
    if(!(this instanceof IteratorFromArray)) {
        throw new Error('请用 new IteratorFromArray()!');
    }
    this._array = arr;
    this._cursor = 0;    
}

IteratorFromArray.prototype.next = function() {
    return this._cursor < this._array.length ?
        { value: this._array[this._cursor++], done: false } :
        { done: true };
}

var iterator = new IteratorFromArray([1,2,3]);

iterator.next();
// { value: 1, done: false }
iterator.next();
// { value: 2, done: false }
iterator.next();
// { value: 3, done: false }
iterator.next();
// { done: ture }

迭代器模式虽然很简单,但同时带来了两个优势,第一它渐进式取得数据的特性可以拿来做延迟运算(Lazy evaluation),让我们能用它来处理大数据结构。第二因为迭代器是数组,所以可以使用所有数组的运算方法像map, filter... 等!

延迟运算是一种运算策略,简单来说我们延迟一个表达式的运算时机直到真正需要它的值在做运算。迭代器模式并没有马上运算,必须等到我们执行next()时,才会真的做运算。

总结

观察者模式迭代器模式有个共通的特性,就是他们都是渐进式(progressive)的取得数据,差别只在于观察者模式是生产者(Producer)推送数据(push ),而迭代器模式是消费者(Consumer)获取数据(pull)!
Observable其实就是这两个模式**的结合,Observable具备生产者推送数据的特性,同时能像序列,拥有数组处理数据的方法(map, filter...)!

Observable一个核心三个重点

  • Operators(操作符) 【核心】
  • Observer(观察者) 【重点】
  • Subject(服从者) 【重点】
  • Schedulers(调用者) 【重点】

Observable 同时可以处理同步与非同步的行为!

观察者Observer

Observable可以被订阅(subscribe),或说可以被观察,而订阅Observable的对象又称为观察者(Observer)。观察者是一个具有三个方法(method)的对象,每当Observable发生事件时,便会执行观察者相对应的方法。

观察者的三个方法(method):

  • next:每当Observable发送出新的值,next方法就会执行。

  • complete:在Observable没有其他的数据可以取得时,complete方法就执行,在complete被调用之后,next方法就不会再起作用。

  • error:每当Observable内发生错误时,error方法就会执行。

complete方法

var observable = Rx.Observable
    .create(function(observer) {
            observer.next('Jerry');
            observer.next('Anna');
            observer.complete();
            observer.next('not work');
    })

// 一个观察者,具备 next, error, complete 三个方法
var observer = {
    next: function(value) {
        console.log(value);
    },
    error: function(error) {
        console.log(error)
    },
    complete: function() {
        console.log('complete')
    }
}

// 用我们定义好的观察者,来订阅这个 observable    
observable.subscribe(observer)

// console输出
// Jerry
// Anna
// complete

error方法

var observable = Rx.Observable
  .create(function(observer) {
    try {
      observer.next('Jerry');
      observer.next('Anna');
      throw 'some exception';
    } catch(e) {
      observer.error(e)
    }
  });

// 一个观察者,具备 next, error, complete 三个方法
var observer = {
    next: function(value) {
        console.log(value);
    },
    error: function(error) {
        console.log('Error: ', error)
    },
    complete: function() {
        console.log('complete')
    }
}

// 用我们定义好的观察者,来订阅这个 observable    
observable.subscribe(observer)

// console输出
// Jerry
// Anna
// Error: some exception

我们也可以直接把next, error, complete三个function依序传入observable.subscribe中,

observable.subscribe(
    value => { console.log(value); },
    error => { console.log('Error: ', error); },
    () => { console.log('complete') }
)

observable.subscribe会在内部自动组成observer对象来操作。

Observable几个重要的观念:

  • Observable可以同时处理同步跟非同步行为

  • Observer是一个对象,这个对象具有三个方法,分别是next , error , complete

  • 订阅一个Observable就像是执行一个function

创建一个Observable

创建操作符(Operator)

  • create

  • of

  • from

  • fromEvent

  • fromEventPattern

  • fromPromise

  • never

  • empty

  • throw

  • interval

  • timer

create

create将subscribe函数转换为实际的Observable。 这相当于调用Observable构造函数。 编写subscribe函数,使其作为一个Observable:它应该调用订阅者的next,error和complate方法,遵循Observable约束;良好的Observable必须调用Subscriber的complate方法一次或其error方法一次,然后再不会调用之后的next。

var source = Rx.Observable
    .create(function(observer) {
        observer.next('Jerry');
        observer.next('Anna');
        observer.complete();
    });

source.subscribe({
    next: function(value) {
        console.log(value)
    },
    complete: function() {
        console.log('complete!');
    },
    error: function(error) {
    console.log(error)
    }
});

// Jerry
// Anna
// complete!

大多数时候,您不需要使用create,因为现有的创建操作符(以及实例组合运算符)允许您为大多数用例创建一个Observable。 但是,create是低级的,并且能够创建任何Observable。

of

of用于创建一个简单的Observable,只发出给定的参数,然后发出完整的通知。 它可以用于与其他Observable组合,如concat。

var source = Rx.Observable.of('Jerry', 'Anna');
source.subscribe({
    next: function(value) {
        console.log(value)
    },
    complete: function() {
        console.log('complete!');
    },
    error: function(error) {
        console.log(error)
    }
});

// Jerry
// Anna
// complete!

默认情况下,它使用一个空的调度程序,这意味着next通知是同步发送,虽然使用不同的调度程序,可以确定这些通知何时将被交付。

from

from将一个数组、类数组(字符串也可以),Promise、可迭代对象,类可观察对象、转化为一个Observable, 可将几乎所有的东西转化一个可观察对象。

var arr = ['Jerry', 'Anna', 2016, 2017, '30 days'] 
var source = Rx.Observable.from(arr);

source.subscribe({
    next: function(value) {
        console.log(value)
    },
    complete: function() {
        console.log('complete!');
    },
    error: function(error) {
        console.log(error)
    }
});

// Jerry
// Anna
// 2016
// 2017
// 30 days
// complete!

如果我们传入Promise对象实例,当正常返回时,就会执行next,并立即完成,如果有错误则会执行error。也可以用fromPromise,会有相同的结果。

注意:offrom接受的参数有些不同,of接受数组形式的参数,但返回还是一个数组。from只能接收一个参数,如果多个参数就会走error。

fromEvent

fromEvent将一个DOM元素上的事件转化为一个Observable

var source = Rx.Observable.fromEvent(document.body, 'click');

source.subscribe({
    next: function(value) {
        console.log(value)
    },
    complete: function() {
        console.log('complete!');
    },
    error: function(error) {
        console.log(error)
    }
});

fromEvent的第一个参数要传入DOM 对象,第二个参数传入要监听的事件名称。next的参数返回就是第一个事件Event对象。

fromEventPattern

要用Event来建立Observable实例还有另一个方法fromEventPattern,这个方法是给自定义事件使用。所谓的自定义事件就是指其行为跟事件相像,同时具有注册监听及移除监听两种行为,就像DOM Event有addEventListener及removeEventListener一样!

function addClickHandler(handler) {
    document.addEventListener('click', handler);
}

function removeClickHandler(handler) {
    document.removeEventListener('click', handler);
}

var clicks = Rx.Observable.fromEventPattern(
    addClickHandler,
    removeClickHandler
);
clicks.subscribe(event => console.log(event));

fromPromise

fromPromise转化一个Promise为一个Obseervable

var promise = new Promise(function (resolve, reject) {
    resolve(42);
});

var source1 = Rx.Observable.fromPromise(promise);

var subscription1 = source1.subscribe(
    function (x) {
        console.log('Next: ' + x);
    },
    function (err) {
        console.log('Error: ' + err);   
    },
    function () {
        console.log('Completed');   
    });

// => Next: 42
// => Completed

将ES2015 Promise转换为Observable。 如果Promise为成功状态,则Observable会将成功的值作为next发出,然后complate。 如果Promise被失败,则输出Observable发出相应的错误。

never

never会给我们一个无穷的observable,如果我们订阅它又会发生什么事呢?...什么事都不会发生,它就是一个一直存在但却什么都不做的observable。

var source = Rx.Observable.never();

source.subscribe({
    next: function(value) {
        console.log(value)
    },
    complete: function() {
        console.log('complete!');
    },
    error: function(error) {
        console.log(error)
    }
});

这个静态操作符对需要创建一个不发射next值、error错误、也不发射complate的简单Observable很有用。 它可以用于测试或与其他Observable组合。 请不要说,从不发出一个完整的通知,这个Observable保持订阅不被自动处置。 订阅需要手动处理。

empty

empty会给我们一个空的observable,如果我们订阅这个observable会发生什么事呢?它会立即送出complete的消息!

var source = Rx.Observable.empty();

source.subscribe({
    next: function(value) {
        console.log(value)
    },
    complete: function() {
        console.log('complete!');
    },
    error: function(error) {
        console.log(error)
    }
});
// complete!

可以直接把empty想成没有做任何事,但它至少会告诉你它没做任何事。该操作符创建一个仅发射‘complete’的通知。通常用于和其他操作符一起组合使用。

throw

throw创建一个只发出error通知的Observable。

var source = Rx.Observable.throw('Oop!');

source.subscribe({
    next: function(value) {
        console.log(value)
    },
    complete: function() {
        console.log('complete!');
    },
    error: function(error) {
    console.log('Throw Error: ' + error)
    }
});
// Throw Error: Oop!

throw操作符对于创建一个只发出error通知的Observable非常有用。它可以用于与其他Observable合并,如在mergeMap中。

interval

interval返回一个以周期性的、递增的方式发射值的Observable, 类似在JS中我们可以用setInterval来建立一个持续的行为一样

var source = Rx.Observable.interval(1000);

source.subscribe({
    next: function(value) {
        console.log(value)
    },
    complete: function() {
        console.log('complete!');
    },
    error: function(error) {
        console.log('Throw Error: ' + error)
    }
});

interval返回一个Observable,它发出一个递增的无限整数序列。第一个参数为时间间隔。 需要注意的是,第一发射不立即发送,而是在第一个周期过去之后发送。 第二个参数,默认情况下,interval使用异步调度程序提供时间概念,但可以将任何调度程序传递给它。

timer

类似于interval,但是第一个参数用来设置发射第一个值得延迟时间

var source = Rx.Observable.interval(1000);

source.subscribe({
    next: function(value) {
        console.log(value)
    },
    complete: function() {
        console.log('complete!');
    },
    error: function(error) {
        console.log('Throw Error: ' + error)
    }
});

timer返回一个Observable,发出一个无限的上升整数序列,第二个参数为时间的间隔。 第一次发射发生在指定的延迟之后。 初始延迟可以是日期。 默认情况下,此运算符使用异步Schuduler提供时间概念,但可以将任何schuduler传递给它。 如果未指定period,则输出Observable仅发出一个值0,否则将发出无限序列。

如果只传递第一个参数,类似在JS中我们可以用setTimeout来建立一个持续的行为一样

Subscription订阅

什么是订阅?订阅是一个表示一次性资源的对象,通常是一个可观察对象的执行。订阅对象有一个重要的方法:unsubscribe,该方法不需要参数,仅仅去废弃掉可观察对象所持有的资源。在以往的RxJS的版本中,"Subscription订阅"被称为"Disposable"。

var observable = Rx.Observable.interval(1000);
var subscription = observable.subscribe(x => console.log(x));
// Later:
// This cancels the ongoing Observable execution which
// was started by calling subscribe with an Observer.
subscription.unsubscribe();

订阅对象有一个unsubscribe()方法用来释放资源或者取消可观察对象的执行