RxJS并非所有订阅者都收到所有活动

时间:2017-11-12 20:04:07

标签: javascript rxjs reactivex reactive

我正在做一个关于RxJS的练习。 并且发生了一些非常奇怪的事情:

  typoStream.subscribe(x => console.log('wont get executed'));
  wordCompletedStream.subscribe(nextStream);
  typoStream.subscribe(x => console.log('will get executed'));

当应用程序运行时,第一个console.log将不会被打印,第二个将会打印 无论流是什么以及它们如何相互作用 - 这都不应该发生,对吧?当我订阅一个observable时,为什么它很重要 - 不管它是否应该向每个订阅者发送事件呢?

如果你想尝试一下: http://embed.plnkr.co/xb8Yimo5RcYGPtgClYgY/

正确输入显示的单词,您可以看到“错误”。但它并不是每次都发生 - 只是大部分时间。

以下是流媒体流:https://photos.app.goo.gl/Z4cpKzekAIuKzMF93

1 个答案:

答案 0 :(得分:2)

我玩了你发布的代码,关键修复是正确组播checkWord observable。您可以像.publish().refCount()一样使用wordStream执行此操作,也可以使用执行相同操作的快捷方式.share()

  const checkStream = wordStream.combineLatest(inputStream).share();

这样做的原因是没有它,checkStream的多个订阅或从它派生的任何流,例如typoStreamwordCompletedStream都会触发wordStreaminputStream的新订阅1}} observable(正确多播,因此没有新请求)和.share() observable,它将在输入上注册新的事件监听器。

使用checkStream运算符,对inputStream或派生的observable进行了多少订阅并不重要,只有第一个订阅会触发对typoStream的订阅。< / p>

请注意,在此修复之后,typoStream的两个订阅者都不会为正确输入的单词触发。这是我所期望的一个名为(() => { // --- UI Stuff, NO NEED TO TOUCH THESE --- // const wordField = $('#TotDWord'); const inputField = $('#TotDInput'); // ----------------------------------------- // // A stream of the users string inputs const inputFieldStream = Rx.Observable.fromEvent(inputField, 'keyup') .map(x => x.target.value).distinctUntilChanged(); // This stream is used to represent the users unput - we don't use the // inputFieldStream directly because we want to manually send values aswell const inputStream = new Rx.Subject(); // Feed the stream from the field into our inputStream inputFieldStream.subscribe(inputStream); // A stream that allows us to manually trigger that we need a new word const nextStream = new Rx.Subject(); // When we want the next word we need to reset the users input nextStream.subscribe(() => { inputField.val(''); inputStream.onNext(''); }); // This stream calls a server for a new random word every time the nextStream emits an event. We startWith a value to trigger the first word const wordStream = nextStream.startWith('') .flatMapLatest(getRandomWord) // publish & refCount cache the result - otherwise every .map on wordStream would cause a new HTTP request .publish().refCount(); // When there is a new word, we display it wordStream.subscribe(word => { wordField.empty(); wordField.append(word); }); // Checkstream combines the latest word with the latest userinput. It emits an array, like this ['the word', 'the user input']; const checkStream = wordStream.combineLatest(inputStream).share(); // Emits an event if the user input is not correct const typoStream = checkStream.filter(tuple => { const word = tuple[0]; const input = tuple[1]; return !word.startsWith(input); }); // When there is a typo we need a new word typoStream.subscribe(nextStream); // Emits an event when the user has entered the entire word correctly const wordCompletedStream = checkStream.filter(tuple => { const word = tuple[0]; const input = tuple[1]; return word == input; }); /** * THIS WILL (MOST OF THE TIME) NOT FIRE WHEN YOU COMPLETE A WORD */ typoStream.subscribe(x => console.log('wont get executed')); // Whenever the word is completed, request a new word wordCompletedStream.subscribe(nextStream); /** * THIS WILL FIRE WHEN YOU COMPLETE A WORD */ typoStream.subscribe(x => console.log('will get executed')); // Calls a server for a random word // returns a promise function getRandomWord() { return $.ajax({ // Change the URL to cause a 404 error url: 'https://setgetgo.com/randomword/get.php' }).promise(); } })();的可观察对象。输入错误字符时,两者都会触发。

Forked Plunkr here

或者看下面的代码:

&#13;
&#13;
<script data-require="jquery" data-semver="3.1.1" src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.6/rx.all.js"></script>

<div>
  <h1>Exercise: Typing of the Dead</h1>
  <div>
    Type the given word correctly and watch the console. Most of the time 1 of the 2 subscriptions on the typoStream will fire (when there should fire none).
  </div>
  <br />
  <div id="TotDWord"></div>
  <input type="text" name="" id="TotDInput" value="" /><span>Highscore: </span><span id="TotDHighscore"></span>
  <div id="TotDScore"></div>
</div>

<script>
  console.clear();
</script>
&#13;
<form id="form1" runat="server">
<asp:Repeater runat="server" ID="rptrInfo" OnItemCommand="Repeater1_ItemCommand" OnItemDataBound="rptrInfo_ItemDataBound">
    <ItemTemplate>
        <asp:Image ID="imgImage" runat="server" ImageUrl='<%#Eval("ImageUrl") %>' />
        <asp:Panel id="pnlVideo" runat="server">
        <video controls height="200" width="385" id="v<%#Eval("Info_Id") %>">
            <source src="<%#Eval("VideoUrl") %>" type="video/mp4" />
        </video>
        </asp:Panel>
    </ItemTemplate>
</asp:Repeater>
&#13;
&#13;
&#13;

相关问题