context = V8::Context.new(timeout: 20000) do |context|
context['ForbidAccess'] = ->(message) { throw NotImplementedError }
end
begin
context.eval("ForbidAccess();")
rescue => e
puts "e.class = #{e.class.name}"
puts "e.causes = #{e.causes}"
puts "e.root_cause = #{e.root_cause}"
puts "e.root_cause.class = #{e.root_cause.class}"
end
控制台输出:
e.class = V8::Error
e.causes = [#<V8::Error: uncaught throw NotImplementedError>, #<ArgumentError: uncaught throw NotImplementedError>]
e.root_cause = uncaught throw NotImplementedError
e.root_cause.class = ArgumentError
如何访问 NotImplementError 对象?
(NotImplementError 仅用于展示。它将被替换为包含消息等的自定义异常。
你可能没有做你认为你在做的事情。throw
关键字不适用于例外情况。它实际上是一个类似于其他语言goto
的本地跳跃。请参阅此代码片段:
catch :done do
while true
array = [1,2,3]
for i in array
if i > 2
throw :done
end
end
end
end
它只是一个控制流结构,其中"捕获"的对象必须与"抛出"的对象匹配。但是你不能简单地捕捉所有的投掷并找出它是哪个物体。对于异常(如NotImplementedError
(,正确的使用方法是raise
:
context = V8::Context.new(timeout: 20000) do |context|
context['ForbidAccess'] = ->(message) { raise NotImplementedError }
end
begin
context.eval("ForbidAccess();")
rescue => e
puts "e.root_cause = #{e.root_cause.inspect}"
# correctly prints #<NotImplementedError: NotImplementedError>
end
至于为什么你在那里看到ArgumentError
,很简单:投掷无法通过begin
- rescue
结构(从异常中拯救(。当未捕获的投掷遇到救援时,会创建一个新的异常。检查以下内容:
begin
throw "whatever"
rescue e
p e #=> ArgumentError: uncaught throw "whatever"
end
这就是内部发生的情况,V8 库看到的所有内容都是弹出的ArgumentError
。