@turbox3d/reactivity
Version:
Large-scale reactive state management library
310 lines (309 loc) • 11.6 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.actionTypeChain = void 0;
exports.createStore = createStore;
exports.store = exports.registerExternalBatchUpdate = void 0;
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _shared = require("@turbox3d/shared");
var _collector = require("./collector");
var _enums = require("../const/enums");
var _reactive = require("./reactive");
var _config = require("../const/config");
var _event2 = require("../utils/event");
var _materialCallStack = require("../utils/materialCallStack");
var _timeTravel = require("./time-travel");
var store;
var actionTypeChain = exports.actionTypeChain = [];
var batchedUpdates = [];
var registerExternalBatchUpdate = exports.registerExternalBatchUpdate = function registerExternalBatchUpdate(obj) {
batchedUpdates.push(obj);
};
function createStore(enhancer) {
if (enhancer !== void 0) {
exports.store = store = enhancer(createStore);
return store;
}
var componentUUIDToListeners = new WeakMap();
function subscribe(listener, uuid, idCustomType) {
var isSubscribed = true;
var obj = componentUUIDToListeners.get(uuid);
if (obj === void 0 || obj.listeners === void 0) {
componentUUIDToListeners.set(uuid, {
idCustomType: idCustomType,
listeners: [listener]
});
} else if (!(0, _shared.includes)(obj.listeners, listener)) {
componentUUIDToListeners.set(uuid, {
idCustomType: idCustomType,
listeners: obj.listeners.concat(listener)
});
}
return function unsubscribe() {
if (!isSubscribed) {
return;
}
isSubscribed = false;
if (componentUUIDToListeners.has(uuid)) {
componentUUIDToListeners["delete"](uuid);
}
};
}
var dirtyJob;
var mutationDepth = 0;
var called = false;
var flushChange = function flushChange(ids, useExternalBatchUpdate, isInner) {
if (!ids.length || _config.ctx.disableReactive) {
return;
}
var pendingObjs = [];
for (var index = 0; index < ids.length; index++) {
var cid = ids[index];
var obj = componentUUIDToListeners.get(cid);
if (obj) {
pendingObjs.push(obj);
}
}
var flush = function flush(idCustomType) {
return function () {
for (var _index = 0; _index < pendingObjs.length; _index++) {
var _obj = pendingObjs[_index];
if (_obj.idCustomType === idCustomType) {
var listeners = _obj.listeners;
for (var j = 0; j < listeners.length; j++) {
var listener = listeners[j];
listener(isInner);
}
}
}
};
};
if (useExternalBatchUpdate) {
batchedUpdates.forEach(function (obj) {
var batchUpdate = obj.handler;
batchUpdate(flush(obj.idCustomType), function () {
// finish batchUpdate
_config.ctx.batchUpdateOnFinish && _config.ctx.batchUpdateOnFinish();
});
});
} else {
// reverse
flush()();
}
};
var keepAliveComputed = function keepAliveComputed(isInner) {
var computedReactionIds = (0, _toConsumableArray2["default"])(_collector.triggerCollector.waitTriggerIds.values()).filter(function (id) {
return id instanceof _reactive.Reaction && !id.lazy && id.computed;
});
if (!computedReactionIds.length) {
return;
}
if (_config.ctx.devTool) {
console.log('keepAlive computed', computedReactionIds);
}
flushChange(computedReactionIds, false, isInner);
// clean wait queue keep alive
(0, _shared.batchRemoveFromSet)(_collector.triggerCollector.waitTriggerIds, computedReactionIds);
};
var immediatelyReactive = function immediatelyReactive(isInner) {
var immediatelyReactionIds = (0, _toConsumableArray2["default"])(_collector.triggerCollector.waitTriggerIds.values()).filter(function (id) {
return id instanceof _reactive.Reaction && !id.computed && id.immediately;
});
if (!immediatelyReactionIds.length) {
return;
}
// clean wait queue
(0, _shared.batchRemoveFromSet)(_collector.triggerCollector.waitTriggerIds, immediatelyReactionIds);
if (_config.ctx.devTool) {
console.log('immediately reactive', immediatelyReactionIds);
}
flushChange(immediatelyReactionIds, false, isInner);
};
var nextTickQueue = [];
var nextTickCaller = function nextTickCaller() {
if (called) {
return;
}
called = true;
var func = function func() {
(0, _shared.nextTick)(function () {
if (mutationDepth > 0) {
called = false;
nextTickQueue.shift();
return;
}
if (nextTickQueue.length === 0) {
return;
}
dirtyJob && dirtyJob();
});
};
nextTickQueue.push(func);
func();
};
var clean = function clean() {
var needClearHistory = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
called = false;
dirtyJob = void 0;
nextTickQueue.shift();
actionTypeChain.length = 0;
needClearHistory && _collector.triggerCollector.endBatch();
};
function dispatch(dispatchedAction) {
var _a, _b, _c, _d;
var payload = dispatchedAction.payload,
type = dispatchedAction.type,
original = dispatchedAction.original,
immediately = dispatchedAction.immediately,
_dispatchedAction$isI = dispatchedAction.isInner,
isInner = _dispatchedAction$isI === void 0 ? false : _dispatchedAction$isI,
domain = dispatchedAction.domain,
name = dispatchedAction.name,
_dispatchedAction$for = dispatchedAction.forceSaveHistory,
forceSaveHistory = _dispatchedAction$for === void 0 ? false : _dispatchedAction$for,
_dispatchedAction$isN = dispatchedAction.isNeedRecord,
isNeedRecord = _dispatchedAction$isN === void 0 ? true : _dispatchedAction$isN;
if (isInner) {
_timeTravel.TimeTravel.processing = true;
}
var syncStackId = _materialCallStack.materialCallStack.push({
type: type,
method: name,
domain: domain === null || domain === void 0 ? void 0 : domain.constructor.name
});
if (!isInner && type !== _enums.EMaterialType.MUTATION && type !== _enums.EMaterialType.UPDATE) {
return;
}
var callback = function callback() {
var ids = (0, _toConsumableArray2["default"])(_collector.triggerCollector.waitTriggerIds.values());
if (!ids.length && !forceSaveHistory) {
clean(false);
return;
}
if (!isInner && isNeedRecord) {
_collector.triggerCollector.save();
}
var computedReactionIds = ids.filter(function (id) {
return id instanceof _reactive.Reaction && id.lazy && id.computed;
});
// do lazy computed reaction first,PS:maybe add new trigger ids
if (_config.ctx.devTool) {
console.log('lazy computed', computedReactionIds);
}
flushChange(computedReactionIds, false, isInner);
var lazyReactiveIds = (0, _toConsumableArray2["default"])(_collector.triggerCollector.waitTriggerIds.values()).filter(function (id) {
return id instanceof _reactive.Reaction && !id.computed && !id.immediately;
});
var restIds = (0, _toConsumableArray2["default"])(_collector.triggerCollector.waitTriggerIds.values()).filter(function (id) {
return !(id instanceof _reactive.Reaction);
});
clean();
// do lazy reactive
if (_config.ctx.devTool) {
console.log('lazy reactive', lazyReactiveIds);
}
flushChange(lazyReactiveIds, false, isInner);
// do Reactive/ReactReactive/CustomReactive
if (_config.ctx.devTool) {
console.log('custom view Reactive', restIds);
}
flushChange(restIds, true, isInner);
};
mutationDepth += 1;
if (isInner || immediately && _collector.triggerCollector.waitTriggerIds.size > 0) {
// flush previous job
dirtyJob && dirtyJob();
}
if (dirtyJob === void 0) {
dirtyJob = callback;
}
var result;
if (_config.ctx.devTool) {
var event = {
domain: (_a = domain === null || domain === void 0 ? void 0 : domain.constructor.name) !== null && _a !== void 0 ? _a : 'UNKNOWN',
method: name,
args: payload,
state: domain === null || domain === void 0 ? void 0 : domain.$$turboxProperties,
time: Date.now(),
stackId: (_b = _materialCallStack.materialCallStack.currentStack) === null || _b === void 0 ? void 0 : _b.stackId
};
_event2.emitter.emit(_event2.EEventName.beforeStoreChange, event);
}
try {
result = original.apply(void 0, (0, _toConsumableArray2["default"])(payload));
} catch (error) {
return error;
}
if (_config.ctx.devTool) {
var _event = {
domain: (_c = domain === null || domain === void 0 ? void 0 : domain.constructor.name) !== null && _c !== void 0 ? _c : 'UNKNOWN',
method: name,
args: payload,
state: domain === null || domain === void 0 ? void 0 : domain.$$turboxProperties,
async: false,
time: Date.now(),
stackId: (_d = _materialCallStack.materialCallStack.currentStack) === null || _d === void 0 ? void 0 : _d.stackId
};
_event2.emitter.emit(_event2.EEventName.afterStoreChange, _event);
}
if ((0, _shared.isPromise)(result)) {
_materialCallStack.materialCallStack.pop(syncStackId);
return new Promise(function (resolve, reject) {
var asyncStackId;
Promise.resolve().then(function () {
asyncStackId = _materialCallStack.materialCallStack.push({
type: type,
method: name,
domain: domain === null || domain === void 0 ? void 0 : domain.constructor.name,
syncStackId: syncStackId
});
});
result.then(function (res) {
var _a, _b;
if (_config.ctx.devTool) {
_event2.emitter.emit(_event2.EEventName.asyncAfterStoreChange, {
domain: (_a = domain === null || domain === void 0 ? void 0 : domain.constructor.name) !== null && _a !== void 0 ? _a : 'UNKNOWN',
method: name,
args: payload,
state: domain === null || domain === void 0 ? void 0 : domain.$$turboxProperties,
async: true,
time: Date.now(),
stackId: (_b = _materialCallStack.materialCallStack.currentStack) === null || _b === void 0 ? void 0 : _b.stackId
});
}
keepAliveComputed(isInner);
immediatelyReactive(isInner);
mutationDepth -= 1;
if (immediately) {
// immediately execute
dirtyJob && dirtyJob();
} else {
nextTickCaller();
}
_materialCallStack.materialCallStack.pop(asyncStackId);
resolve(res);
})["catch"](function (error) {
reject(error);
});
});
}
keepAliveComputed(isInner);
immediatelyReactive(isInner);
mutationDepth -= 1;
if (isInner || immediately) {
// immediately execute
dirtyJob && dirtyJob();
_timeTravel.TimeTravel.processing = false;
} else {
nextTickCaller();
}
_materialCallStack.materialCallStack.pop(syncStackId);
return result;
}
return {
dispatch: dispatch,
subscribe: subscribe
};
}