与其他“FRP”库不同,Rx 不会防止故障:使用时间不匹配的数据调用的回调。有解决此问题的好方法吗?
举个例子,假设我们有一系列从单个流派生的昂贵计算(例如,我们在下面进行排序或 ajax 获取,而不是 _.identity)。我们执行 distinctUntilChanged 以避免重新计算昂贵的东西。
sub = new Rx.Subject();
a = sub.distinctUntilChanged().share();
b = a.select(_.identity).distinctUntilChanged().share();
c = b.select(_.identity).distinctUntilChanged();
d = Rx.Observable.combineLatest(a, b, c, function () { return _.toArray(arguments); });
d.subscribe(console.log.bind(console));
sub.onNext('a');
sub.onNext('b');
第二个事件最终会导致一些故障状态:我们输出了三个事件,而不是一个,这会浪费大量 CPU,并且需要我们明确地解决不匹配的数据。
可以通过删除 distinctUntilChanged 并编写一些古怪的 scan() 函数来绕过这个特定示例,以在输入未更改的情况下传递先前的结果。然后您可以压缩结果,而不是使用 combineLatest。这很笨拙,但可行。
但是,如果任何地方都存在异步,例如ajax 调用,然后 zip 不起作用:ajax 调用将同步(如果缓存)或异步完成,因此您不能使用 zip。
编辑
尝试用一个更简单的例子来阐明期望的行为:
您有两个流,a 和 b。 b 取决于 a。 b 是异步的,但浏览器可能会缓存它,因此它可以独立于 a 更新,也可以与 a 同时更新。因此,浏览器中的特定事件可能会导致以下三种情况之一:更新; b 更新; a 和 b 都更新。所需的行为是在所有三种情况下只调用一次回调(例如渲染方法)。
zip 不起作用,因为当 a 或 b 单独触发时,我们不会从 zip 获得任何回调。 combineLatest 不起作用,因为当 a 和 b 一起触发时,我们会得到两个回调。
最佳答案
概念
both a and b update
a 和 b 都是可观察的,在 Rx 中不作为原语存在。
没有可以定义的无损通用运算符来决定何时从 a 收到通知,是应该将通知传递到下游还是推迟到收到来自 b<>。 Rx 中的通知本身不携带“两者”语义,或任何超出 Rx 语法的语义。
此外,Rx 的串行合约会阻止运算符(operator)利用重叠通知来实现此目标。 (尽管我怀疑依赖竞争条件并不是您想要的方法。)
参见 Rx Design Guidelines 中的 §§4.2、6.7 .
因此,我上面所说的“没有可以定义的无损通用运算符……”的意思是给定两个具有独立的可观察量 a 和 b通知,任何试图决定何时从 a 或 b 收到通知的运算符(operator)是必须立即推送还是等待“其他”值,必须依赖任意时间.这是猜测。因此,这个假设的运算符必须要么丢弃值(例如,DistinctUntilChanged 或 Throttle),要么丢弃时间(例如,Zip 或 Buffer),尽管可能是两者的某种组合。
因此,如果代理有能力单独推送a,或者单独推送b,或者a和b 一起作为通知单元,那么开发人员有责任自己具体化通知单元的概念。
需要三态类型:a |乙 | {a,b}
(请原谅我糟糕的 JS)
var ab = function(a, b) { this.a = a; this.b = b; }
sub.onNext(new ab('a')); // process a alone
sub.onNext(new ab('a', 'b')); // process a and b together
sub.onNext(new ab(null, 'c')); // process c alone
observable 查询的形状不再重要。观察者必须被定义为接受这种数据类型。生成器有责任根据其内部状态的语义应用任何必要的缓冲或计时计算,以便为其观察者生成正确通知。
顺便说一下,感谢您在您的编辑中提供了一个简单的解释(反正我觉得很清楚)。我第一次听说“故障”是在 this Rx forum discussion 中.如您所见,它从未真正结束。现在我想知道 OP 的问题是否真的这么简单,当然假设我已经正确理解了你的问题。 :-)
更新:
这是另一个相关的讨论,包括我对为什么 Rx 不是 FRP 的更多想法:
关于javascript - 如何避免 Rx 中的故障,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22332407/
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时
作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack