spine/spine — pull request #558 by adambiggs (2014-09-10 20:34:15+00:00)
Title: Refactored model event dispatching

I've been thinking about this refactor for a while now. Did some de-linting as i went, sorry if it makes the code harder to review...

This PR contains 2 main changes:

#### Instance Event Dispatching
Model instances now trigger their own events and store their own callbacks in the root record. This should benefit performance a lot when binding many instance events, since there's no need to loop through every single callback whenever an event is triggered.

When an instance triggers an event, it propagates up to the class:

```coffee
SomeModel.on 'update', (record)-> # Called with record1
record1.on 'update', (record)-> # Called with record1
record2.on 'update', (record)-> # Not called

record1.updateAttribute 'attr', 'value'
```

#### Event Changes
Events now work slightly differently between models and records:

- `'refresh'`: When a model is refreshed, it triggers this event as usual, but now each record also triggers it's own `'refresh'` event. This was my biggest motivation for the refactor. Previously, if you wanted to do something when an individual record was modified on the server, you would have to loop through all the refreshed records to find the one you're interested in. If you have lots of controllers doing this, and lots of records being refreshed, this could become a huge bottleneck...

```coffee
SomeModel.on 'refresh', (records)-> # Called with [record1, record2]
record1.on 'refresh', (record)-> # Called with record1
record2.on 'refresh', (record)-> # Called with record2
record3.on 'refresh', (record)-> # Not called

SomeModel.refresh JSON.stringify [record1, record2]
```

- `'change'`: Along with `'create'`, `'update'`, and `'destroy'`, this event is now triggered when a model is refreshed. This means `'change'` is triggered every time the model or record changes (makes sense right?). In a future update I see this event being powered by `Object.observe()`, passing a map of changed attributes or not being fired if no attributes are modified.

Very much open to ideas/questions/criticism as this contains some pretty big core changes. I've tested this in our app's codebase, but not thoroughly, and it could probably use some more unit tests.