maxtaco / coffee-script

IcedCoffeeScript
http://maxtaco.github.com/coffee-script
MIT License
727 stars 58 forks source link

`try catch` structure with async code #83

Open layerssss opened 11 years ago

layerssss commented 11 years ago

I found #35 is also about error handling. But here I mean handling Exceptions instead of Async Errors.

What I'm trying to achieve is let the exception in the following code be caught.

try
  await setTimeout defer(), 100
  throw new Error 'let me be caught'
  alert "Hello CoffeeScript!"
catch e
  alert "error: #{e.message}"

ICS had already done so many async good with the while, if/else, for structures. Hope we can also enjoy them with the try/catch structure.

doublerebel commented 10 years ago

Interesting. Could what you are proposing here:

try
  await setTimeout defer(), 100
  throw new Error 'let me be caught'
  alert "Hello CoffeeScript!"
catch e
  alert "error: #{e.message}"

Be the Iced shorthand equivalent to this:

error_fn = (e) ->
  alert "error: #{e.message}"

try
  setTimeout (=>
    try
      throw new Error 'let me be caught'
      alert "Hello CoffeeScript!"
    catch e
      error_fn.call this, e
  ), 100
catch e
  error_fn.call this, e

So let's look at a more complex example from the main docs:

# Search for the most popular food and the most
# popular weather pattern in parallel.
w_list = [ "sun", "rain", "snow", "sleet" ]
f_list = [ "tacos", "burritos", "pizza", "shrooms" ]

try
  await
    rankPopularity w_list, defer weather
    rankPopularity f_list, defer food

  # If we got results for both, do a final search
  if weather.length and food.length
    await search "#{weather[0]}+#{food[0]}", defer tweets
    msg = tweets[0]?.text

  # Alert the results to the browser
  alert if msg? then msg else "<nothing found>"

catch e
  alert "error: #{e.message}"

Would need to be compiled to:

# Search for the most popular food and the most
# popular weather pattern in parallel.
w_list = [ "sun", "rain", "snow", "sleet" ]
f_list = [ "tacos", "burritos", "pizza", "shrooms" ]

o = {}
n_out = 0
nothing = "<nothing found>"
error_fn = (e) ->
  alert "error: #{e.message}"

cb_generator = (field, ctx) ->
  n_out++
  (json) ->
    try
      o[field] = json
      if --n_out is 0
        # If we got results for both, do a final search
        if o.weather.length and o.food.length
          search "#{o.weather[0]}+#{o.food[0]}", (tweets) ->
            try
              # Alert the results to the browser
              msg = tweets[0]?.text
              alert if msg? then msg else nothing
            catch e
              error_fn.call ctx, e
        else
          alert nothing
    catch e
      error_fn.call ctx, e

try
  rankPopularity w_list, cb_generator "weather", this
  rankPopularity f_list, cb_generator "food", this
catch e
  error_fn.call this, e

The number of try/catch blocks, especially with the extra variables required, could certainly cause a performance hit, as noted here and on JSPerf , but that may not be noticeable outside of large fns and loops.

txdv commented 10 years ago

Make it optional then. dtry, dcatch and dfinally which work with async code.

This is really a bummer, because now I have to check after every await call for errors, this puts iced behind C#/Saltarelle functionality.

lorenz commented 9 years ago

Any chance that that is getting added? I'd really like it for something like that:

try await
  for name, size of sizes
    transformStream = sharpJpegStream(size)
    rawImage.pipe transformStream
    transformStream.pipe storageBackend.store("#{id}-#{name}.jpg")
    transformStream.on "finished", defer _
    transformStream.on "error", throw new Error("Something went wrong!")
catch e
  storageBackend.delete("#{id}-#{name}.jpg",defer _) for name, _ of sizes await
  next new Error("Something went wrong!")

This is next to impossible to get working with the current error handling because it throws errors on events which should then trigger the catch function.