2013-04-15 3 views
4

콜백 대신 지연 가능한 사용의 이점은 무엇입니까? 작은 예.지연 가능한 대 콜백 인터페이스

# 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에는 중첩 수준이 2 개 있으며 콜백에는 세 개가 있습니다.

필자가 볼 수 있듯이 Deferrable 객체를 사용하면 예를 들어 errback을 전달하고 콜백 만 정의 할 수 있습니다. 어떤 경우에는 의미가 있기 때문에 코드가 적어지고 코드가 적어지고 코드가 더 읽기 쉽게됩니다.

하지만. 나는 성가신 사건을 한 번 발견했다. 예를 들어,이 가짜 비동기 API가 있습니다. 해야는 콜백 모드

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 

에 보이는 방법

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 

심지어 지금은 (내 취향) 약간 청소기를 보인다. 그러나 감사 주관적입니다. 상상해보십시오. 여러분은 비동기식 API보다 synchronouse API를 지원할 것입니다.

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 

당신 그래서에게 : 콜백 만 속에서의 싸움은 정말 비동기 작전에 섬유를 호출 할 때 지연 가능 인터페이스를 사용하면, (매우 큰 작업과 지원이 매우 무거운 편이다) 섬유로 연기 응답을 가진 모든 방법을 포장한다 파이버에서 소켓을 감싸고 비동기 코드가 synchronouse가되었습니다. 속에서의 싸움은 정말 당신은 또한 모든 블록 방법을 재정의해야한다고 말했다합니다 : 그것은 작은 변화이지만,

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의 표준입니다. 어쩌면 내가 뭔가를 오해하고, 연기 가능한 방식을 잘못 사용합니까? 어쩌면 콜백 인터페이스 냄새와 나쁜 문제가있어?

추 신 : EventMachine의 MongoDB 드라이버에서 작업 중이므로 지금은 클라이언트에 synchronouse 인터페이스를 추가하기 때문에 모든 것을 썼습니다. 그리고 결국 Deferrables 때문에 콜백에 다시 쓰려고 생각하면서 모든 공용 API에 원숭이 패치를 적용하여 동기화 지원을 추가해야한다는 것을 깨달았습니다. 이것은 당신이이 같은 동기 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 

: 당신이 Deferrable의 인터페이스를 제어하는 ​​경우

답변

1

, 당신의 라인을 따라 뭔가 할 수

response = NeworkIO.get.sync 
+0

을하지만 당신은 할 수 콜백 인터페이스와 같은 일을 :) – fl00r

+0

아마 내가 당신의 질문을 이해하지 못합니다. 좀 더 간결하고 구체적인 것을 물어보기 위해 그것을 다시 말해 줄 수 있습니까? – Jacob

+0

제 질문은 꽤 일반적입니다. API를 사용하면 동기 인터페이스를 지원하기가 더 복잡하고 어려워지면 왜 Deferrables를 사용해야합니까? – fl00r