observable.subscribe 有三个对象 next,error,和 complete
observable.subscribe({
next: value => console.log(`Value is ${value}`),
error: err => console.log(err),
complete: () => console.log(`Completed`),
})
该.subscribe功能也可以具有三个功能,而不是一个对象。
observable.subscribe(
value => console.log(`Value is ${value}`),
err => console.log(err),
() => console.log(`Completed`)
)
我们可以通过创建一个对象来创建一个新的observable,传入一个subscriber(也称为观察者)的函数。该用户有三种方法:next,error,和complete。订户可以调用下一个与一个值作为根据需要很多次,complete或者error在端部。调用complete或后error,可观察对象将不会将任何值向下推。
import { Observable } from 'rxjs'
const observable$ = new Observable(function subscribe(subscriber) {
const intervalId = setInterval(() => {
subscriber.next('hi');
subscriber.complete()
clearInterval(intervalId);
}, 1000);
});
observable$.subscribe(
value => console.log(`Value is ${value}`),
err => console.log(err)
)
上面的示例将 Value is hi 在1000毫秒后打印。
RxJS具有创建可观察对象的许多功能。一些最常用的是of,from 和 ajax
of 接受一系列值并将其转换为流
of(1, 2, 3, 'Hello', 'World').subscribe(value => console.log(value))
// 1 2 3 Hello World
from 将所有内容转换为流
import { from } from 'rxjs'
from([1, 2, 3]).subscribe(console.log)
// 1 2 3
from(new Promise.resolve('Hello World')).subscribe(console.log)
// 'Hello World'
from(fibonacciGenerator).subscribe(console.log)
// 1 1 2 3 5 8 13 21 ...
ajax 接受字符串URL或创建一个发出HTTP请求的可观察对象。ajax有一个函数 ajax.getJSON ,该函数仅从AJAX调用返回嵌套的响应对象,而没有由返回的其他任何属性ajax():
ajax('https://jsonplaceholder.typicode.com/todos/1').subscribe(console.log)
// {request, response: {userId, id, title, completed}, responseType, status}
ajax.getJSON('https://jsonplaceholder.typicode.com/todos/1').subscribe(console.log)
// {userId, id, title, completed}
ajax({ url, method, headers, body }).subscribe(console.log)
// {...}
Operators
Operators 是RxJS的真正强大之处,它具有可满足您几乎所有需要的运算符。从RxJS 6开始,运算符不是可观察对象上的方法,而是使用.pipe方法应用于可观察对象上的纯函数。
map 采用单个参数函数,并在流中的每个元素上应用投影:
of(1, 2, 3, 4, 5).pipe(
map(i=> i * 2)
).subscribe(console.log)
// 2, 4, 6, 8, 10
filter 接受一个参数,并从流中删除为 给定函数返回false 的值
of(1, 2, 3, 4, 5).pipe(
map(i => i * i),
filter(i => i % 2 === 0)
).subscribe(console.log)
// 4, 16
flatMap 采用一个函数,将流(steam)中的每个项目映射到另一个流中,并展平这些流的所有值:
of(1, 2, 3).pipe(
flatMap(page => ajax.toJSON(`https://example.com/blog?size=2&page=${page}`)),
).subscribe(console.log)
// [ { blog 1 }, { blog 2 }, { blog 3 }, { blog 4 }, { blog 5 }, { blog 6 } ]
merge 合并 两个流 中的项目,按到达的顺序
merge(
interval(150).pipe(take(5), mapTo('A')),
interval(250).pipe(take(5), mapTo('B'))
).subscribe(console.log)
// A B A A B A A B B B
redux-observable
redux 中的 所有操作都是同步的。 redux-observable 是 redux 的中间件,它使用 可观察的流 执行 异步工作,然后使用该异步工作的结果 在Redux 中 dispatch 另外一个 action.
Redux-observable 是 基于 Epics 的思想,一个epic 是一个function,它接受一系列的action,并且 可选 的产生 一个状态流 (a stream of state),并且返回 一系列 action。
function (action$:Observable,state$:StateObservable):Observable;
按照约定, 作为 steam(流)的每个变量 都以 结尾 **$ **。
下面 有个 ping-pong epic 例子: 携带一个 ping 请求服务,然后请求完成后,接收一个 pong 到 app中。
const pingEpic =action$=>action$.pipe(
ofType('PING'),
flatMap(action=>ajax('https://example.com/pinger')),
mapTo({type:'PONG'})
)
现在,我们将通过添加epics和检索用户来更新原始的Todo store。
import { combineReducers, createStore } from 'redux'
import { ofType, combineEpics, createEpicMiddleware } from 'redux-observable';
import { map, flatMap } from 'rxjs/operators'
import { ajax } from 'rxjs/ajax'
//...
/* user 和 todos reducers 定义 如上 */
const rootReducer = combineReducers({ user, todos })
const epicMiddleware = createEpicMiddleware();
const userEpic=action$=>action$.pipe(
ofType('GET_USER'),
flatMap(()=>ajax.getJSON('https://foo.bar.com/get-user')),
map(user=>({type:'GET_USER_SUCCESS',payload:user}))
)
const addTodoEpic=action$=>action$.pipe(
ofType('ADD_TODO'),
flatMap(()=>ajax({
url:'https://foo.bar.com/add-todo',
method:'POST',
body:{text:action.payload}
})),
map(data=>data.response),
map(todo=>({type:'ADD_TODO_SUCCESS',payload:todo}))
)
const completeTodoEpic=action$=>action$.pipe(
ofType('COMPLETE_TODO'),
flatMap(()=>ajax({
url:'https://foo.bar.com/add-todo',
method:'POST',
body:{id:action.payload}
})),
map(data=>data.response),
map(todo=>({type:'COMPLETE_TODO_SUCCESS',payload:todo}))
)
const rootEpic = combinEpic (userEpic,addTodoEpic,completeTodoEpic)
const store = createStore(rootReducer,applyMiddleware(epicMiddleware))
epicMiddleware.run(rootEpic);
注意: Epic 和 RxJS 中的其他 observable streams 一样 ,它们最终会 处于 complete 或 error 的状态,然后 epic 和app 将后停止 工作,因此可以使用 catchError 抓住潜在的错误 反应式TODO 应用-github源码