我正试图在我的小项目中使用drakma-async
。但我就是不明白发生了什么。(我使用emacs+slime+ccl)。我需要使用http获取数据,并在回调中对其进行解析。我想我可能会得到无法解析的错误数据,所以我想重试。但当我试着做一些测试时,我就是不明白发生了什么。。。
(defun my-callback (data)
(prin1 data)
(restart-case
(error "Some error parsing data...")
(just-continue () (prin1 "Continue..."))))
(defun simple-test ()
(let ((future (asf:make-future)))
(as:delay #'(lambda () (asf:finish future "Some data")) :time 2)
(prin1 (asf:future-finished-p future))
(asf:attach future #'my-callback)))
(defun drakma-test ()
(asf:alet ((response (das:http-request "http://www.google.com")))
;(prin1 (asf:future-finished-p response))
(asf:attach response #'my-callback)))
(defun drakma-test-let ()
(let ((response (das:http-request "http://www.google.com")))
;(prin1 (asf:future-finished-p response))
(asf:attach response #'my-callback)))
(defun run-test (test)
(as:start-event-loop test))
1) 所以我会的,这就是我的简单例子(这就是我计划的)
? (run-test #'simple-test)
NIL"Some data" ;I get debugger here with simple-error and choose my restart
Invoking restart: #<RESTART JUST-CONTINUE #x7F0578EC20AD>
"Continue..."
1
2) 这是我在第二次测试中得到的:
? (run-test #'drakma-test)
"<A LOT OF HTML>
"
1
我的调试器和重新启动在哪里?
3) 在drakma-test
中取消注释;(prin1 (asf:future...))
行
? (run-test #'drakma-test)
1
没有完成/未完成的bool,没有数据未打印,我没有重新启动,结果我只得到1
。
4) 我想如果我写(let ((reponse (das:http-request "http://www.google.com"))) ... )
在(asf:alet ...)
的instad中,response
将不包含future
对象,而是将阻塞,直到请求完成并且response
将包含数据。
? (run-test #'drakma-test-let)
1
5) 在drakma-test-let
中取消注释;(prin1 (asf:future...))
行
? (run-test #'drakma-test-let)
NIL ;future is not finished
1
数据没有打印出来,只是没有完成和运行测试的结果。
我已经运行了cl-async的测试,除了ipv6测试外,它们都通过了。所以我不知道从哪里开始了解发生了什么。。。为什么我没有调试程序并在第二次测试中重新启动?为什么在第三次测试中没有发生任何事情(与第二次测试相同,但与prin1相同)。为什么在第五次和第五次测试中什么都没发生?
附言:没有足够的信誉为这些库创建drakma-async
或cl-async
标记。我知道drakma-async
是在drakma
之上构建的,所以我加上了这个标签。
感谢m-n的评论,它使情况变得更清楚,并很快解释了情况。
我举了一些例子,想展示每种情况下会发生什么:
示例:
(defun my-callback (&rest data)
(format t "Echo from callback: ~A~%" data)
(restart-case
(error "Some error parsing data...")
(just-continue () (prin1 "Continue..."))))
(defun my-errback (e)
(format t "Echo from errback: ~A~%" e))
(defun make-example-future ()
(let ((future (asf:make-future))) ;creating future
(as:delay #'(lambda () ;finishing future in 2 seconds
(asf:future-handler-case ;wrapping asf:finish
(asf:finish future
"Result data")
(t (e) (asf:signal-error future e)))) ;signal future an error
:time 2)
future))
(defun simple-test-2 ()
(let ((future (make-example-future)))
(format t "Is future?: ~A~%Finished?: ~A~%"
(asf:futurep future) (asf:future-finished-p future))
(asf:alet ((result future))
(asf:attach-errback future #'my-errback)
(format t "Finished? ~A~%" (asf:future-finished-p future))
(asf:future-finished-p result)
(asf:attach result #'my-callback))))
下面是正在发生的事情:
? (as:start-event-loop #'simple-test-2)
Is future?: T
Finished?: NIL
;<here we have a 2 sec pause>
Finished? T
Echo from errback: There is no applicable method for the generic function:
#<STANDARD-GENERIC-FUNCTION CL-ASYNC-FUTURE:FUTURE-FINISHED-P #x302001B67A8F>
when called with arguments:
("Result data")
A) asf:alet
等待结果并将结果值绑定到变量。所以我错误地认为asf:alet
绑定了一个未来。
B) 在make-example-future
中,我们用asf:future-handler-case
包裹asf:finish
并使用CCD_ 21向未来发送错误。这意味着错误被处理,并且errback
将被调用。即使回调在代码的后面附加。此外,(asf:future-finished-p result)
的错误用future-handler-case
处理,因为它被包裹在asf:alet
中(至少我认为是这样)。
C) 注释(asf:future-finished-p result)
,结果为
Is future?: T
Finished?: NIL
Finished? T
Echo from callback: (Result data) ;here is my data
Echo from errback: Some error parsing data... ;;here is my error
1
在CCD_ 27中有类似的CCD_ 28包装器来包装CCD_ 29。
这就解释了#2
的测试结果。我得到了数据,asf:alet
返回了字符串。回调的错误被传递给了errback
,但我没有。此外在仅使用asf:alet
的drakma-test
中,我无法连接errback
,因为我无法访问未来。我需要在let
中调用http-request
,而不是在alet
中。
这也解释了#3
测试的结果:我在发送给errback
的(future-finished-p)
中出错。
如果我们用新的my-callback
看#4
和#5
测试的结果:可以看出cl-async
尝试使用drakma
返回的所有值来调用我的回调。其中有7个(drakma:http-request
返回的值)。因此,我试图附加错误数量的参数回调,而我的#4和#5测试发出了一个错误信号,该错误只是由future-hander-case
处理并发送到errback
。
结果:无论如何,在不删除future-handler-case
的情况下使用drakma-async
的重新启动似乎是不可能的,因为它会将错误发送到errback,但会丢失所有重新启动。
如果有人当面回答我的问题,希望这篇文章能有所帮助。