4
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

如何访问 NotImplementedError 对象?

(NotImplementedError 只是为了展示。它将被包含消息等的自定义异常替换。)

4

1 回答 1

2

你可能没有做你认为你正在做的事情。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那里,这很简单: throw 无法通过begin-rescue结构(从异常中拯救)。当未捕获的 throw 遇到救援时,会创建一个关于它的新异常。检查以下:

begin
  throw "whatever"
rescue e
  p e   #=> ArgumentError: uncaught throw "whatever"
end

这就是内部发生的事情,所有 V8 库看到的都是一个ArgumentError弹出窗口。

于 2014-10-05T23:26:16.723 回答