使用Deferrable而不是回调有什么好处。小例子。
# This is Deferrable interface
request = NetworkIO.get
request.callback do |resp|
puts "Job is done"
end
request.errback do |err|
puts "Oh. My name is Forest, Forest Gump"
end
# And this is callback interface
NetworkIO.get do |resp|
if Exception === resp
puts "Oh. My name is Forest, Forest Gump"
else
puts "Job is done!"
end
end
# Or node js style
NetworkIO.get do |err, resp|
if err
puts "Oh. My name is Forest, Forest Gump"
else
puts "Job is done!"
end
end
Deferrable有两个嵌套级别,而回调有三个嵌套级别。
正如我所看到的,使用Deferrable对象,您可以传递errback,例如,仅定义回调。这在某些情况下是有意义的,因此代码变得更易读,代码行数更少,嵌套更少。
但是。我发现了一个令人讨厌的案子。例如,你有这个假的异步API。
class SomeIO
def find(msg)
response = DeferrableResponse.new
req = socket.send(msg)
req.callback do |data|
response.succeed(data)
end
req.errback do |err|
response.fail(err)
end
response
end
def count(msg)
response = DeferrableResponse.new
req = find(msg)
req.callback do |data|
response.succeed(data.size)
end
req.errback do |err|
response.fail(err)
end
response
end
end
如何在回调模式下看起来
class SomeIO
def find(msg, &blk)
socket.send(msg) do |resp|
blk.call(resp)
end
end
def count(msg, &blk)
find(msg) do |resp|
if Exception === resp
blk.call(resp)
else
cnt = resp.size
blk.call(cnt)
end
end
end
end
即使是现在,它看起来更清洁(根据我的口味)。但这是主观欣赏。想象一下,您将支持异步API上的同步API。使用Deferrable Interface,您应该将所有方法都包含在Fiber中的可延迟响应(这是非常大的工作并且非常重要以支持),而在回调中,您必须仅在trully async ops上调用Fibers:
class SyncSomeIO < SomeIO
def find(msg, &blk)
fib = Fiber.current
socket.send(msg) do |resp|
fib.resume(resp)
end
res = Fiber.yield
raise res if res === Exception
res
end
end
所以你刚刚将你的套接字包装在Fiber中,你的异步代码变成了同步。 Trully说你还应该重新定义所有的块方法:
class SomeIO
...
def count(msg, &blk)
find(msg) do |resp|
if Exception === resp
block_given? ? blk.call(resp) : resp
else
cnt = resp.size
block_given? ? blk.call(cnt) : cnt
end
end
end
end
这是一个小小的改动,但只需几行代码,您的API就可以同步和异步模式工作。
很抱歉这么大的介绍,谢谢你们阅读(你们两个人)。
问题是。 Deferrable是事实上是Ruby中的事件api的标准。也许我误解了一些东西,而且我使用了Deferrable错误的方式?也许回调接口闻起来并且有一些不好的问题?
PS:我写了这一切,因为我正在使用EventMachine上的MongoDB驱动程序,现在正在向客户端添加synchronouse接口。并最终意识到我应该修补所有公共API以添加同步支持,因为Deferrables并且考虑在回调上重写它。
答案 0 :(得分:1)
如果您控制Deferrable
的界面,您可以执行以下操作:
class DeferrableResponse
def sync
fiber = Fiber.current
callback { |val| fiber.resume(val) }
errback { |err| fiber.resume(err) }
result = Fiber.yield
raise result if result.is_a? Exception
result
end
end
这将允许您使用这样的同步API:
response = NeworkIO.get.sync