mirror of
https://github.com/sveltejs/svelte.git
synced 2024-11-30 00:46:29 +01:00
d2f8e472a5
Adds optional performance support for apps using an immutable data structure such as redux. Adds the `immutable` boolean option for compile and an `immutable` option to store as well. When these options are used, computed will not recompute if the object has not changed. If your data structure is not immutable you should not use this as svelte cannot know if a mutation was made on objects. This PR also adds support for Dates and NaN values so computed properties will not recompute if a date has not changed or a value did not change from NaN. This closes out these issues: * https://github.com/sveltejs/svelte/issues/1146 * https://github.com/sveltejs/svelte/issues/1161 This is my first PR for Svelte. Any feedback would be appreciated!
225 lines
4.7 KiB
JavaScript
225 lines
4.7 KiB
JavaScript
function noop() {}
|
|
|
|
function assign(target) {
|
|
var k,
|
|
source,
|
|
i = 1,
|
|
len = arguments.length;
|
|
for (; i < len; i++) {
|
|
source = arguments[i];
|
|
for (k in source) target[k] = source[k];
|
|
}
|
|
|
|
return target;
|
|
}
|
|
|
|
function blankObject() {
|
|
return Object.create(null);
|
|
}
|
|
|
|
function destroy(detach) {
|
|
this.destroy = noop;
|
|
this.fire('destroy');
|
|
this.set = this.get = noop;
|
|
|
|
if (detach !== false) this._fragment.u();
|
|
this._fragment.d();
|
|
this._fragment = this._state = null;
|
|
}
|
|
|
|
function differs(a, b) {
|
|
if (a == null || b == null) return a !== b;
|
|
if (a.constructor !== b.constructor) return true;
|
|
if (a.valueOf && b.valueOf) {
|
|
a = a.valueOf();
|
|
b = b.valueOf();
|
|
}
|
|
if (typeof a === 'number' && isNaN(a) && isNaN(b)) return false;
|
|
return a !== b || typeof a === 'object' || typeof a === 'function';
|
|
}
|
|
|
|
function dispatchObservers(component, group, changed, newState, oldState) {
|
|
for (var key in group) {
|
|
if (!changed[key]) continue;
|
|
|
|
var newValue = newState[key];
|
|
var oldValue = oldState[key];
|
|
|
|
var callbacks = group[key];
|
|
if (!callbacks) continue;
|
|
|
|
for (var i = 0; i < callbacks.length; i += 1) {
|
|
var callback = callbacks[i];
|
|
if (callback.__calling) continue;
|
|
|
|
callback.__calling = true;
|
|
callback.call(component, newValue, oldValue);
|
|
callback.__calling = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
function fire(eventName, data) {
|
|
var handlers =
|
|
eventName in this._handlers && this._handlers[eventName].slice();
|
|
if (!handlers) return;
|
|
|
|
for (var i = 0; i < handlers.length; i += 1) {
|
|
handlers[i].call(this, data);
|
|
}
|
|
}
|
|
|
|
function get(key) {
|
|
return key ? this._state[key] : this._state;
|
|
}
|
|
|
|
function init(component, options) {
|
|
component._observers = { pre: blankObject(), post: blankObject() };
|
|
component._handlers = blankObject();
|
|
component._bind = options._bind;
|
|
|
|
component.options = options;
|
|
component.root = options.root || component;
|
|
component.store = component.root.store || options.store;
|
|
}
|
|
|
|
function observe(key, callback, options) {
|
|
var group = options && options.defer
|
|
? this._observers.post
|
|
: this._observers.pre;
|
|
|
|
(group[key] || (group[key] = [])).push(callback);
|
|
|
|
if (!options || options.init !== false) {
|
|
callback.__calling = true;
|
|
callback.call(this, this._state[key]);
|
|
callback.__calling = false;
|
|
}
|
|
|
|
return {
|
|
cancel: function() {
|
|
var index = group[key].indexOf(callback);
|
|
if (~index) group[key].splice(index, 1);
|
|
}
|
|
};
|
|
}
|
|
|
|
function on(eventName, handler) {
|
|
if (eventName === 'teardown') return this.on('destroy', handler);
|
|
|
|
var handlers = this._handlers[eventName] || (this._handlers[eventName] = []);
|
|
handlers.push(handler);
|
|
|
|
return {
|
|
cancel: function() {
|
|
var index = handlers.indexOf(handler);
|
|
if (~index) handlers.splice(index, 1);
|
|
}
|
|
};
|
|
}
|
|
|
|
function set(newState) {
|
|
this._set(assign({}, newState));
|
|
if (this.root._lock) return;
|
|
this.root._lock = true;
|
|
callAll(this.root._beforecreate);
|
|
callAll(this.root._oncreate);
|
|
callAll(this.root._aftercreate);
|
|
this.root._lock = false;
|
|
}
|
|
|
|
function _set(newState) {
|
|
var oldState = this._state,
|
|
changed = {},
|
|
dirty = false;
|
|
|
|
for (var key in newState) {
|
|
if (differs(newState[key], oldState[key])) changed[key] = dirty = true;
|
|
}
|
|
if (!dirty) return;
|
|
|
|
this._state = assign({}, oldState, newState);
|
|
this._recompute(changed, this._state);
|
|
if (this._bind) this._bind(changed, this._state);
|
|
|
|
if (this._fragment) {
|
|
dispatchObservers(this, this._observers.pre, changed, this._state, oldState);
|
|
this._fragment.p(changed, this._state);
|
|
dispatchObservers(this, this._observers.post, changed, this._state, oldState);
|
|
}
|
|
}
|
|
|
|
function callAll(fns) {
|
|
while (fns && fns.length) fns.shift()();
|
|
}
|
|
|
|
function _mount(target, anchor) {
|
|
this._fragment.m(target, anchor);
|
|
}
|
|
|
|
function _unmount() {
|
|
if (this._fragment) this._fragment.u();
|
|
}
|
|
|
|
var proto = {
|
|
destroy: destroy,
|
|
get: get,
|
|
fire: fire,
|
|
observe: observe,
|
|
on: on,
|
|
set: set,
|
|
teardown: destroy,
|
|
_recompute: noop,
|
|
_set: _set,
|
|
_mount: _mount,
|
|
_unmount: _unmount
|
|
};
|
|
|
|
/* generated by Svelte vX.Y.Z */
|
|
function a(x) {
|
|
return x * 2;
|
|
}
|
|
|
|
function b(x) {
|
|
return x * 3;
|
|
}
|
|
|
|
function create_main_fragment(state, component) {
|
|
|
|
return {
|
|
c: noop,
|
|
|
|
m: noop,
|
|
|
|
p: noop,
|
|
|
|
u: noop,
|
|
|
|
d: noop
|
|
};
|
|
}
|
|
|
|
function SvelteComponent(options) {
|
|
init(this, options);
|
|
this._state = assign({}, options.data);
|
|
this._recompute({ x: 1 }, this._state);
|
|
|
|
this._fragment = create_main_fragment(this._state, this);
|
|
|
|
if (options.target) {
|
|
this._fragment.c();
|
|
this._fragment.m(options.target, options.anchor || null);
|
|
}
|
|
}
|
|
|
|
assign(SvelteComponent.prototype, proto);
|
|
|
|
SvelteComponent.prototype._recompute = function _recompute(changed, state) {
|
|
if (changed.x) {
|
|
if (differs(state.a, (state.a = a(state.x)))) changed.a = true;
|
|
if (differs(state.b, (state.b = b(state.x)))) changed.b = true;
|
|
}
|
|
};
|
|
|
|
export default SvelteComponent;
|