Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Can't get `this` from within a callback #45

Closed
pitr opened this Issue Nov 19, 2012 · 5 comments

Comments

Projects
None yet
2 participants

pitr commented Nov 19, 2012

Some libraries, instead of passing data as arguments to a callback, use "call" to yield data as this. For example:

getUser = (user_id, cb) -> cb.call(id: user_id, user_id)

await getUser 42, defer user
alert(user)

It is impossible to get this using defer keyword.

Collaborator

malgorithms commented Nov 19, 2012

Unless I'm misunderstanding this model, I think you could call like so:

await getUser 42, {call: defer user}
alert user

i.e., make this "cb" object you describe and put the defer into cb.call

Does this work?

Collaborator

malgorithms commented Nov 19, 2012

Assuming that what I just proposed works, I think the only thing to be careful of is that defers are (1) only to be called once, and (2) must always be called, or you'll leak callbacks.

I've never seen this library you mention, but if it's emitting multiple calls to cb.call, or if it doesn't call cb.call in certain circumstances, defer() isn't what you want.

pitr commented Nov 20, 2012

The library I had in mind was Nohm. It has one short form that is described over here: http://maritz.github.com/nohm/#short_forms

User.load 1, ->
  alert @p('name')

Though it's just sugar for another way of fetching a model, it nonetheless illustrates the fact that there is data loss happening when using await/defer.

In your example you are overwriting Function.prototype.call, which, while works, sounds wrong.

Collaborator

malgorithms commented Nov 20, 2012

Hi Pitr, sorry, I see what you're saying now!

Technically await/defer are for functions that use the callback w/data as arguments model. If you encounter another type of function, such as what you describe above, you have 2 options:

  1. just not use await/defer; iced coffee does not force your whole project to use them.
  2. Make a one-liner wrapper function that packages results await/defer friendly.

For an example of #2, it's pretty easy:

myGetUser = (user_id, cb) -> getUser user_id, (uid) -> cb @

Now I can await/defer to my heart's content:

await
   myGetUser 42, defer user42
   myGetUser 69, defer user69
console.log "Loaded 42 and 69 concurrently."

Notice it simply emits data in the more iced-coffee-script way. It's up to you whether you want to bother with that.

I found myself doing this once with a DB library that called back with one of two functions, onSuccess or onError. I ended up writing something like this (over-simplified):

query = (str,cb) ->
  db.query(str, {
    onSuccess: (rows) -> cb null, rows
    onError: (err) -> cb err,  null
  })

Now I could just use it everywhere:

await
  query 'SELECT 1', defer err1, one
  query 'SELECT 2', defer err2, two

I've found that I rarely have to do this kind of thing, but when I do, I just put it into my own little library and then have access to the 3rd party library with the convenience of await/defer.

pitr commented Nov 21, 2012

That makes sense. Thank you.

@pitr pitr closed this Nov 21, 2012

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment