Observable 包装

    用 Observable 包装意味着接收一些非 Observable 的东西并将其转换为 Observable,这样就可以很好的与其它 Observable 配合使用。同样还意味着现在我们可以使用操作符了。

    这里我们需要做的三件事:发出数据错误处理关闭流

    1. if(request.status === 200) {
    2. observer.next( request.response ) // 发出数据
    3. }

    处理潜在的错误

    1. else {
    2. observer.error('error happened');
    3. }
    1. console.clear();
    2. const { Observable } = Rx;
    3. const speechRecognition$ = new Observable(observer => {
    4. const speech = new webkitSpeechRecognition();
    5. speech.onresult = (event) => {
    6. observer.next(event);
    7. observer.complete();
    8. };
    9. speech.start();
    10. return () => {
    11. speech.stop();
    12. }
    13. });
    14. const say = (text) => new Observable(observer => {
    15. const utterance = new SpeechSynthesisUtterance(text);
    16. observer.next(e);
    17. observer.complete();
    18. };
    19. speechSynthesis.speak(utterance);
    20. });
    21. const button = document.querySelector("button");
    22. const heyClick$ = Observable.fromEvent(button, 'click');
    23. heyClick$
    24. .switchMap(e => speechRecognition$)
    25. .map(e => e.results[0][0].transcript)
    26. .map(text => {
    27. switch (text) {
    28. case 'I want':
    29. return 'candy';
    30. case 'hi':
    31. case 'ice ice':
    32. return 'baby';
    33. case 'hello':
    34. return 'Is it me you are looking for';
    35. case 'make me a sandwich':
    36. case 'get me a sandwich':
    37. return 'do it yo damn self';
    38. case 'why are you being so sexist':
    39. return 'you made me that way';
    40. default:
    41. return `I don't understand: "${text}"`;
    42. }
    43. })
    44. .concatMap(say)
    45. .subscribe(e => console.log(e));

    语音识别流

    1. const speechRecognition$ = new Observable(observer => {
    2. const speech = new webkitSpeechRecognition();
    3. speech.onresult = (event) => {
    4. observer.complete();
    5. };
    6. speech.start();
    7. return () => {
    8. speech.stop();
    9. });

    这段代码建立了语音识别 API,然后等待响应,并在响应一次后完成流,很像第一个使用 AJAX 的示例。

    注意还定义一个函数用来清理

    函数 say 负责发出你想要表达的语音。

    1. const say = (text) => new Observable(observer => {
    2. const utterance = new SpeechSynthesisUtterance(text);
    3. utterance.onend = (e) => {
    4. observer.next(e);
    5. observer.complete();
    6. };
    7. speechSynthesis.speak(utterance);
    8. });

    主体流 hey$

    1. heyClick$
    2. .switchMap(e => speechRecognition$)
    3. .map(e => e.results[0][0].transcript)
    4. .map(text => {
    5. switch (text) {
    6. case 'I want':
    7. return 'candy';
    8. case 'hi':
    9. case 'ice ice':
    10. return 'baby';
    11. case 'hello':
    12. return 'Is it me you are looking for';
    13. case 'make me a sandwich':
    14. case 'get me a sandwich':
    15. return 'do it yo damn self';
    16. case 'why are you being so sexist':
    17. return 'you made me that way';
    18. default:
    19. return `I don't understand: "${text}"`;
    20. }
    21. })
    22. .subscribe(e => console.log(e));

    整体逻辑应该是这样的:点击按钮激活 heyClick$speechRecognition$ 监听我们说了什么并把结果发送给 heyClick$ 的转换逻辑,转换逻辑的结果将由 say Observable 发出声音。

    这两个 Observable 包装示例其中一个是简单些的 Ajax,而另一个是有一点点高级的语音 API 。但原理都是相同的: 1)数据是通过调用 next() 来发送的 2)如果没有更多的数据要发送则调用 complete() 3)如果有需要的话,定义一个清理函数可以通过 来调用 4)在合适的地方通过调用 error() 来进行错误处理。(只在第一个示例中这样做了)