ckknight / gorillascript

GorillaScript is a compile-to-JavaScript language designed to empower the user while attempting to prevent some common errors.
MIT License
300 stars 34 forks source link

Cannot use async in promise! block #122

Closed unc0 closed 11 years ago

unc0 commented 11 years ago

I'm trying to wrap nodejs request module into promise, but it's callback use three arguments, so I tried use async err, res, body <- request... in promise! block instead of to-promise! macro. But it will throw a TypeError in runtime.

Test code here, npm install request --production

require! request
let x()
  let ret = promise!
    async err, res, body <- request.get 'http://www.google.com'
    if err?
      yield rejected! 'failed to get this url'
    if res.status-code is 302
      yield fulfilled! 'redirected'
    else
      yield fulfilled! body
  return ret

let on(x)-> console.log x

x().then(on, on)
ckknight commented 11 years ago

Hmm, yeah, it should instead give a compile-time error, since the block following async will be a non-generator state.

unc0 commented 11 years ago

since the block following async will be a non-generator state.

How to wrap this non nodejs style callback to promise?

ckknight commented 11 years ago

There's two ways to do what you're doing:

require! request
let x()
  promise!
    // if you want to deal with an error from this yield, wrap it in a try-catch.
    let body = yield to-promise! request.get 'http://www.google.com'
    if res.status-code is 302
      'redirected'
    else
      body

let on(x)-> console.log x

x().then(on, on)

or if you want to keep the async:

require! request
let x()
  let {promise, fulfill, reject} = __defer()
  returning promise
  async err, body <- request.get 'http://www.google.com'
  if err?
    reject err
  else if res.status-code is 302
    fulfill 'redirected'
  else
    fulfill body

let on(x)-> console.log x

x().then(on, on)

I recommend the first one.

unc0 commented 11 years ago

I tried the first one, got [ReferenceError: res is not defined].

ckknight commented 11 years ago

Oh, shoot, I didn't realize there were two arguments.

I'm going to add a to-promise-array! macro that acts like to-promise! except that it stuffs the second and onward arguments into an array (except for the first one, which is assumed to be an error to be rejected with) rather than just evaluating to the second argument.

ckknight commented 11 years ago

Here you go, with a fancy new macro:

require! request
let x()
  promise!
    // if you want to deal with an error from this yield, wrap it in a try-catch.
    let [res, body] = yield to-promise-array! request.get 'http://www.google.com'
    if res.status-code is 302
      'redirected'
    else
      body

let on(x) console.log x

x().then(on, on)
unc0 commented 11 years ago

Cool, issue solved!