Skip to content
New issue

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

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Asynchronous on change handlers #29

Merged
merged 4 commits into from
Mar 9, 2015
Merged

Asynchronous on change handlers #29

merged 4 commits into from
Mar 9, 2015

Conversation

charypar
Copy link
Member

@charypar charypar commented Mar 5, 2015

Add support for on-change on a cursor to return a promise. Anyone can start an update transaction with start-transaction. Any updates to the cursor in between that call and a subsequent call to end-transaction passing the transaction obtained from start-transaction may trigger one or more on-change handlers. Those handlers may rely on asynchronous calls. If they do, they can now return a promise, which they resolve when their asynchronous behaviour is done. All promises returned by the on-change handlers are collected on all running transactions and the call to end-transaction returns a promise waiting for all of them to finish (using bluebird's .all). If no change handlers were registered or no promises were returned the end-transaction call will return a resolved promise.

This is useful in multiple scenarios and simplifies dealing with asynchronous calls in state observers. For instance, using this, Reflex can wait for even asynchronous change handlers to finish what they are doing before rendering server side. In the same way, application initialisation can trigger an async on-change with a state update and Reflex will wait until it is finished before rendering (no need for an explicit done callback in start or route initialisation).

To Do

  • basic transaction logic
  • better check for promise
  • integrate into server-side rendering

@charypar
Copy link
Member Author

charypar commented Mar 6, 2015

Ok, tested with the following app.start:

start: (app-state) ->
  # Form async update test
  channels = app-state.get \channels
  channels.on-change (ch) ->
    console.log "Channels updated!"

    key = last keys ch
    return if ch[key].name is "troll"

    bluebird.delay 50
    .then ->
      console.log "Renaming the channel..."
      channels.update ->
        it[key] import name: "troll"
        it

i.e. whenever channels get updated, change the last channel's name to "troll" after 50 ms (unless it already is "troll").

Works like a charm. Notice start doesn't get a callback any more. It doesn't need one and neither do route init functions. All the asynchronous behaviour can be handled through state observers now.

It does however get tricky not to create observation cascades and cycles, we should try and come up with a best practice. I can see one major rule: Always observe a different path than you update in response.

@charypar charypar changed the title Asynchronous on change handler Asynchronous on change handlers Mar 6, 2015
@charypar
Copy link
Member Author

charypar commented Mar 8, 2015

@tabazevedo @StuartHarris this is now ready to merge.

tabazevedo pushed a commit that referenced this pull request Mar 9, 2015
Asynchronous on change handlers
@tabazevedo tabazevedo merged commit 568a3bd into master Mar 9, 2015
@tabazevedo tabazevedo deleted the onchange-async branch March 9, 2015 16:38
@charypar charypar mentioned this pull request Apr 7, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants