如何正确使用IcedCoffeeScript处理错误?(How to correctly handl

2019-08-06 19:47发布

它是在node.js中常见的做法是返回错误消息作为第一个参数的回调函数。 有许多在纯JS(无极,步骤,序列等),但它们都没有这个问题的解决方案似乎是积与ICS。 什么是正确的解决方案来处理错误而不损失太多的可读性?

例如:

# makes code hard to read and encourage duplication
await socket.get 'image id', defer err, id
if err # ...
await Image.findById id, defer err, image
if err # ...
await check_permissions user, image, defer err, permitted
if err # ...


# will only handle the last error
await  
  socket.get 'image id', defer err, id
  Image.findById id, defer err, image
  check_permissions user, image, defer err, permitted

if err  # ...


# ugly, makes code more rigid
# no way to prevent execution of commands if the first one failed
await  
  socket.get 'image id', defer err1, id
  Image.findById id, defer err2, image
  check_permissions user, image, defer err3, permitted

if err1 || err2 || err3  # ...

Answer 1:

我通过样式和编码约定解决这个问题。 而且它拿出所有的时间。 让我们以下面的代码片段,充实了一点点,使我们拥有一个可行的功能。

my_fn = (cb) ->
  await socket.get 'image id', defer err, id
  if err then return cb err, null
  await Image.findById id, defer err, image
  if err then return cb err, null
  await check_permissions user, image, defer err, permitted
  if err then return cb err, null
  cb err, image

你说得对,这是丑陋的,因为你是短路了,在许多地方的代码,你需要记住每次返回时调用CB。

你给我的其他片段产生不正确的结果,因为他们将推出在需要序列化并行。

我的个人ICS编码约定是:(1)从函数返回只有一次(控制脱落的端部); (2)尽量全部缩进同一级别来处理错误。 重写你有什么,在我喜欢的风格:

my_fn = (cb) ->
  await socket.get 'image id', defer err, id 
  await Image.findById id, defer err, image                   unless err?
  await check_permissions user, image, defer err, permitted   unless err?
  cb err, image

在socket.get调用错误的情况下,你需要检查错误的两倍,这将明显失败两次。 我不认为这是世界的末日,因为它使代码更清洁。

或者,你可以这样做:

my_fn = (autocb) ->
  await socket.get 'image id', defer err, id
  if err then return [ err, null ]
  await Image.findById id, defer err, image
  if err then return [ err, null ]
  await check_permissions user, image, defer err, permitted
  return [ err, image ]

如果您使用autocb,这不是我喜欢的ICS功能,那么编译器会当你返回/短路了功能要求你的autocb。 我觉得这种结构更容易出错的经验。 例如,假设你需要获得在函数开始的锁,现在你需要释放了N次。 其他人可能不同意。

另外一个说明,在下面的评论中指出。 autocb就像return ,它仅接受一个值。 如果你想返回多个值在这个例子中,你需要返回一个数组或字典。 defer确实解构分配来这里帮助你:

await my_fn defer [err, image]


Answer 2:

正如所讨论的问题#35的IcedCoffeeScript库的,还有基于冰式连接器 ,其是作为输入的回调/延迟功能的另一种技术,并返回另一个回调/推迟。

试想一下,你的项目有一个标准订单的参数回调:第一个参数始终是错误,这是成功空。 此外,进一步假设,你想在错误的第一个迹象离开的功能。

第一步是使一个连接器,我打电话的“ErrorShortCircuiter”或“ESC”:

{make_esc} = require 'iced-error'

这是实现像这样:

make_esc = (gcb, desc) -> (lcb) ->
    (err, args...) ->
        if not err? then lcb args...
        else if not gcb.__esc
            gcb.__esc = true
            log.error "In #{desc}: #{err}"
            gcb err

要了解这是什么做的,考虑如何使用它的一个例子:

my_fn = (gcb) ->
    esc = make_esc gcb, "my_fn"
    await socket.get 'image id', esc defer id
    await Image.findById id, esc defer image
    await check_permissions user, image, esc defer permitted
    gcb null, image

这个版本my_fn第一作出了ErrorShortCircuiter(或esc ),其任务是双重的:(1)火gcb与此错误对象; (2)记录一条有关该错误发生的地点以及是什么错误消息。 很显然,你应该有所不同根据您设定的确切行为。 然后,所有后续调用库函数与回调将给出由生成回调defer像往常一样,然后通过运行esc连接器,这将改变的回调的行为。 新的行为是调用gcb全局的功能上的错误,并让当前await成功完成块。 此外,在更迭的情况下,有没有需要处理一个空的错误对象,所以才有了后来的槽(如idimage ,和permitted )的填写。

这种技术是非常强大的,可定制的。 其核心思想是,通过所产生的回调defer是真正的延续和可以改变整个程序的后续控制流程。 他们可以在图书馆这样做,这样你就可以得到你需要许多不同类型的应用程序,与不同的约定在库调用错误行为。



文章来源: How to correctly handle errors with IcedCoffeeScript?