{"action":"created","issue":{"url":"https://api.github.com/repos/emberjs/ember.js/issues/10501","labels_url":"https://api.github.com/repos/emberjs/ember.js/issues/10501/labels{/name}","comments_url":"https://api.github.com/repos/emberjs/ember.js/issues/10501/comments","events_url":"https://api.github.com/repos/emberjs/ember.js/issues/10501/events","html_url":"https://github.com/emberjs/ember.js/pull/10501","id":58476466,"number":10501,"title":"[WIP] Implement Glimmer Engine","user":{"login":"wycats","id":4,"avatar_url":"https://avatars.githubusercontent.com/u/4?v=3","gravatar_id":"","url":"https://api.github.com/users/wycats","html_url":"https://github.com/wycats","followers_url":"https://api.github.com/users/wycats/followers","following_url":"https://api.github.com/users/wycats/following{/other_user}","gists_url":"https://api.github.com/users/wycats/gists{/gist_id}","starred_url":"https://api.github.com/users/wycats/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wycats/subscriptions","organizations_url":"https://api.github.com/users/wycats/orgs","repos_url":"https://api.github.com/users/wycats/repos","events_url":"https://api.github.com/users/wycats/events{/privacy}","received_events_url":"https://api.github.com/users/wycats/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":21,"created_at":"2015-02-21T21:49:32Z","updated_at":"2015-03-03T23:57:30Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/emberjs/ember.js/pulls/10501","html_url":"https://github.com/emberjs/ember.js/pull/10501","diff_url":"https://github.com/emberjs/ember.js/pull/10501.diff","patch_url":"https://github.com/emberjs/ember.js/pull/10501.patch"},"body":"Glimmer is the next-generation rendering engine for Ember.js. Built on top of HTMLBars, streams, and an entirely rewritten view layer, Glimmer offers the best performance of any of the major JavaScript frameworks while remaining backwards compatible with Ember 1.x apps.\r\n\r\n---\r\n\r\nThe Virtual DOM showed the world that render-time diffing delivers awesome performance by minimizing DOM updates and keeping unchanged elements stable. But like any abstraction, it comes with a cost. In this case, constructing the virtual DOM to compare requires at least some subset of components do a full re-render, and building virtual DOM nodes for static areas of your markup that will never change for every change requires many more allocations and increases GC pressure.\r\n\r\nGlimmer analyzes templates at compile time, relying on the fact that Handlebars' declarative syntax clearly differentiates between static areas, which make up the majority of a template, and the dynamic areas that can change. Instead of invoking a `render()` method and diffing the result, Glimmer only walks the (much smaller) existing dynamic tree.\r\n\r\n---\r\n\r\nHandlebars' declarative syntax means that from the perspective of an app, the template is being \"re-rendered every time\", but we can take advantage of static knowledge to reduce the work that we need to do. User code, like helpers and computed properties, are executed during the walk, but only to get (primitive) **values** which can be `===` compared, not to build up a new tree. **In other words, the programming model is equivalent to \"render every time\", but we take advantage of the declarative nature of Ember's APIs to reduce work**.\r\n\r\nInternally, instead of creating a virtual DOM, Glimmer builds a tree of streams, each stream pointing to a node in the DOM. On initial render, we teack the last value (always a primitive) that we inserted into the DOM. The streams are not exposed to application code; Glimmer executes user code when necessary and pushes the new value into the stream.\r\n\r\nWhen re-rendering, we walk the tree and flush the streams. If the primitive value produced by the stream has not changed, we do nothing. If it has changed, we write the change to the DOM. **Like Virtual DOM approaches, this is a \"write-only\" algorithm**.\r\n\r\nOne of the benefits of this approach is that **we can naturally fuse the Ember/Polymer model of observing individual properties with the React model of explicitly re-rendering areas of the template**. No matter what happens, the process of revalidation walks the tree, looking for dirty nodes, and revalidates any dirty nodes it finds.\r\n\r\nThe only difference is how much of dynamic tree is marked dirty before revalidation begins. Also, because observation can only dirty dynamic nodes (and schedule a top-down revalidation), multiple observers and re-renders that occur during a single run-loop still only produce **a single batch of DOM updates**.\r\n\r\nIn essence, the biggest difference between Glimmer and traditional virtual DOM approaches is that we diff values, not DOM. This approach not only lets us avoid the algorithmic complexity of tree diffing (instead, we just `===` check two values), it also lets us avoid doing many render-time allocations.\r\n\r\n[Slides from the talk at EmberConf](http://f.cl.ly/items/0t031v2Z3y001V1N0F3N/Virtual%20DOM.pdf)\r\n\r\n### Work List\r\n\r\n(this looks like more things than it actually is)\r\n\r\n- [x] merge subscription change into our branch\r\n- [x] linkRenderNode can mark stability\r\n- [x] Ember should return true from `linkRenderNode`\r\n- [x] make sure all child streams correctly disconnect from parents\r\n- [x] add stream pruning logic that correctly prunes ancestors\r\n- [x] add scope teardown hook to HTMLBars (recursive upon `clear` or `remove`)\r\n  - [ ] this is also responsible for view layer teardown\r\n- [x] Propagate correct visitor through descendent hooks (so dirty checks can be avoided for a subtree)\r\n- [x] Do not dirty check render nodes that were just created (fixes regression)\r\n- [x] Add \"classify\" hook to decide which hook `content` et al should delegate to\r\n- [x] Make sure that #view is idempotent\r\n- [x] Components and views should create a new scope frame\r\n  - [x] Implement custom scope in Ember (so that ambient `view`, `controller`, etc. can be stored)\r\n  - [x] Eliminate `*component*` hacks\r\n- [x] Lifecycle hooks on the renderer\r\n- [x] Move code duplicated between `#view`, `#component` and `Ember.View` into the Renderer\r\n- [ ] Support reflecting attributes onto angle-bracket components\r\n- [ ] Pass mutable bindings as \"mutator\" objects\r\n- [ ] Support `foo={{action \"bar\"}}`\r\n- [ ] Legacy support: Implement unknownProperty/setUnknownProperty to work with mutator objects\r\n  - [ ] Deprecate setting non-`mut` attributes, and support `(mut foo)` sexprs in legacy Handlebars syntax\r\n- [ ] Investigate executing teardown callbacks at a \"quiescent\" state (\"vent plasma\")\r\n  - [ ] Make sure to consider the rpflo stress test situation\r\n- [x] Implement a `zip` and `map` abstraction for streams to clean up ad hoc stream creation\r\n- [ ] Add tests for memory leaks\r\n- [ ] Make sure that custom render functions that mutate the buffer continue to work\r\n- [ ] `options.template` should not exist if there is no template\r\n- [ ] feature flag all the things"},"comment":{"url":"https://api.github.com/repos/emberjs/ember.js/issues/comments/77066219","html_url":"https://github.com/emberjs/ember.js/pull/10501#issuecomment-77066219","issue_url":"https://api.github.com/repos/emberjs/ember.js/issues/10501","id":77066219,"user":{"login":"morenoh149","id":587438,"avatar_url":"https://avatars.githubusercontent.com/u/587438?v=3","gravatar_id":"","url":"https://api.github.com/users/morenoh149","html_url":"https://github.com/morenoh149","followers_url":"https://api.github.com/users/morenoh149/followers","following_url":"https://api.github.com/users/morenoh149/following{/other_user}","gists_url":"https://api.github.com/users/morenoh149/gists{/gist_id}","starred_url":"https://api.github.com/users/morenoh149/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/morenoh149/subscriptions","organizations_url":"https://api.github.com/users/morenoh149/orgs","repos_url":"https://api.github.com/users/morenoh149/repos","events_url":"https://api.github.com/users/morenoh149/events{/privacy}","received_events_url":"https://api.github.com/users/morenoh149/received_events","type":"User","site_admin":false},"created_at":"2015-03-03T23:57:30Z","updated_at":"2015-03-03T23:57:30Z","body":"@toblender yeah. I thought he meant `teach`"}}