Ruby 可延迟与回调接口

Ruby 可延迟与回调接口,ruby,asynchronous,eventmachine,Ruby,Asynchronous,Eventmachine,使用可延迟而不是回调的好处是什么。小例子 # 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 d

使用可延迟而不是回调的好处是什么。小例子

# 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有两个嵌套级别,而回调有三个嵌套级别

正如我所看到的,例如,使用可延迟对象,您可以传递errback,并只定义callback。这在某些情况下是有意义的,因此代码变得更可读,代码行更少,嵌套更少

但是。我发现了一个恼人的案子。例如,您得到了这个伪异步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
就我的口味而言,即使现在它看起来也有点干净。但它是主观的。想象一下,您将支持SynchronouseAPI而不是异步API。使用可延迟接口,您应该将所有具有可延迟响应的方法包装到光纤中(这是一项非常大的工作,需要非常繁重的支持),而在回调中,您必须仅在trully async ops上调用光纤:

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
这是一个很小的改变,但只需几行代码,您的API就可以在同步和异步模式下工作

抱歉这么大的介绍,谢谢你们的阅读(你们两个)

问题是。Deferrable实际上是Ruby中事件api的标准。也许我误解了什么,我用了错误的方法?也许回调接口有异味,并且出现了一些不好的问题


PS:我写这一切是因为我正在EventMachine上开发MongoDB驱动程序,现在正在向客户端添加synchronouse接口。并最终意识到,由于延迟,我应该对所有公共API进行修补,以添加同步支持,并考虑在回调时重写它。

如果您控制
延迟的接口,您可以按照以下方式执行操作:

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

但是你可以用回调接口做同样的事情:)也许我不理解你的问题。你能不能换一种说法,问一些更简洁、更具体的问题?我的问题相当笼统:如果延迟使API更复杂,更难在其上支持同步接口,为什么我需要使用延迟呢。
response = NeworkIO.get.sync