- Observable 包装
- 包装 ajax 调用
- 发出数据
- 处理潜在的错误
- 关闭流
- 包装语音音频 API
- 语音识别流
- 语音合成, say
- 主体流 hey$
- 总结
- 包装 ajax 调用
Observable 包装
在 Observable 剖析章节中我们只学到了关键操作符 next()、error() 和 complete(),如果是我们自己定义的 Observable 的话,可以使用这些方法来驱动 Observable 。我们还学到了,这些方法会触发相应的回调函数。
用 Observable 包装意味着接收一些非 Observable 的东西并将其转换为 Observable,这样就可以很好的与其它 Observable 配合使用。同样还意味着现在我们可以使用操作符了。
包装 ajax 调用
let stream = Rx.Observable.create((observer) => {let request = new XMLHttpRequest();request.open( ‘GET’, ‘url’ );request.onload =() =>{if(request.status === 200) {observer.next( request.response );observer.complete();} else {observer.error('error happened');}}request.onerror = () => {observer.error('error happened')}request.send();})stream.subscribe((data) => console.log( data ))
这里我们需要做的三件事:发出数据、错误处理和关闭流
发出数据
if(request.status === 200) {observer.next( request.response ) // 发出数据}
处理潜在的错误
else {observer.error('error happened');}
关闭流
if(request.status === 200) {observer.next( request.response )observer.complete() // 关闭流,因为我们不想要更多的数据了}
包装语音音频 API
console.clear();const { Observable } = Rx;const speechRecognition$ = new Observable(observer => {const speech = new webkitSpeechRecognition();speech.onresult = (event) => {observer.next(event);observer.complete();};speech.start();return () => {speech.stop();}});const say = (text) => new Observable(observer => {const utterance = new SpeechSynthesisUtterance(text);utterance.onend = (e) => {observer.next(e);observer.complete();};speechSynthesis.speak(utterance);});const button = document.querySelector("button");const heyClick$ = Observable.fromEvent(button, 'click');heyClick$.switchMap(e => speechRecognition$).map(e => e.results[0][0].transcript).map(text => {switch (text) {case 'I want':return 'candy';case 'hi':case 'ice ice':return 'baby';case 'hello':return 'Is it me you are looking for';case 'make me a sandwich':case 'get me a sandwich':return 'do it yo damn self';case 'why are you being so sexist':return 'you made me that way';default:return `I don't understand: "${text}"`;}}).concatMap(say).subscribe(e => console.log(e));
语音识别流
这将激活浏览器的麦克风并记录我们的语音
const speechRecognition$ = new Observable(observer => {const speech = new webkitSpeechRecognition();speech.onresult = (event) => {observer.next(event);observer.complete();};speech.start();return () => {speech.stop();}});
这段代码建立了语音识别 API,然后等待响应,并在响应一次后完成流,很像第一个使用 AJAX 的示例。
注意还定义一个函数用来清理
return () => {speech.stop();}
所以我们可以通过调用 speechRecognition.unsubscribe() 来清理系统资源
语音合成, say
函数 say 负责发出你想要表达的语音。
const say = (text) => new Observable(observer => {const utterance = new SpeechSynthesisUtterance(text);utterance.onend = (e) => {observer.next(e);observer.complete();};speechSynthesis.speak(utterance);});
主体流 hey$
heyClick$.switchMap(e => speechRecognition$).map(e => e.results[0][0].transcript).map(text => {switch (text) {case 'I want':return 'candy';case 'hi':case 'ice ice':return 'baby';case 'hello':return 'Is it me you are looking for';case 'make me a sandwich':case 'get me a sandwich':return 'do it yo damn self';case 'why are you being so sexist':return 'you made me that way';default:return `I don't understand: "${text}"`;}}).concatMap(say).subscribe(e => console.log(e));
整体逻辑应该是这样的:点击按钮激活 heyClick$ 。speechRecognition$ 监听我们说了什么并把结果发送给 heyClick$ 的转换逻辑,转换逻辑的结果将由 say Observable 发出声音。
这一切归功于 @ladyleet 和 @benlesh
总结
这两个 Observable 包装示例其中一个是简单些的 Ajax,而另一个是有一点点高级的语音 API 。但原理都是相同的: 1)数据是通过调用 next() 来发送的 2)如果没有更多的数据要发送则调用 complete() 3)如果有需要的话,定义一个清理函数可以通过 unsubscribe() 来调用 4)在合适的地方通过调用 error() 来进行错误处理。(只在第一个示例中这样做了)
