109 lines
2.6 KiB
JavaScript
109 lines
2.6 KiB
JavaScript
import { action, intercept, keys, runInAction, toJS } from "mobx";
|
|
import globalStore from "./global";
|
|
|
|
const storeHistory = [];
|
|
let cursor = -1;
|
|
|
|
// ENHANCE: 使用性能更好的方案
|
|
// 比较历史记录
|
|
function _isEqual(objA, objB) {
|
|
const cacheSet = new Set();
|
|
function _isCommonObject(obj) {
|
|
if (typeof obj !== "object" || obj === null) {
|
|
return false;
|
|
}
|
|
const unRegularConstructors = [Promise, Map, Set, WeakMap, WeakSet];
|
|
return !unRegularConstructors.some((c) => obj instanceof c);
|
|
}
|
|
function _deepEqual(obj1, obj2) {
|
|
if (!_isCommonObject(obj1) || !_isCommonObject(obj2)) {
|
|
return obj1 === obj2;
|
|
}
|
|
if (obj1 === obj2) {
|
|
return true;
|
|
}
|
|
if (cacheSet.has(obj1) || cacheSet.has(obj2)) {
|
|
return false;
|
|
}
|
|
cacheSet.add(obj1);
|
|
cacheSet.add(obj2);
|
|
const keys1 = Object.keys(obj1);
|
|
const keys2 = Object.keys(obj2);
|
|
if (keys1.length !== keys2.length) {
|
|
return false;
|
|
}
|
|
return keys1.every((key) => _deepEqual(obj1[key], obj2[key]));
|
|
}
|
|
return _deepEqual(objA, objB);
|
|
}
|
|
|
|
// 在历史记录中漫游
|
|
function go(span) {
|
|
const newCursor = Math.min(
|
|
Math.max(0, cursor + span),
|
|
storeHistory.length - 1
|
|
);
|
|
console.log("go ", span);
|
|
if (newCursor === cursor) {
|
|
return;
|
|
}
|
|
cursor = newCursor;
|
|
console.log("gone to ", newCursor);
|
|
Object.assign(globalStore, storeHistory[newCursor]);
|
|
}
|
|
|
|
function clearHistory() {
|
|
storeHistory.length = 0;
|
|
cursor = -1;
|
|
}
|
|
|
|
// 包装mobx的action以实现历史记录
|
|
function executeAction(actionFunc, ...args) {
|
|
actionFunc.apply(this, args);
|
|
const current = toJS(globalStore);
|
|
if (!_isEqual(storeHistory[cursor], current)) {
|
|
storeHistory[++cursor] = current;
|
|
storeHistory.length = cursor + 1;
|
|
console.log(
|
|
"pushed history, length & cursor: ",
|
|
storeHistory.length,
|
|
cursor
|
|
);
|
|
if (storeHistory.length > 256) {
|
|
storeHistory.splice(0, 256 - storeHistory.length);
|
|
}
|
|
}
|
|
}
|
|
function wrappedAction(...args) {
|
|
let name, func;
|
|
if (typeof args[0] === "function") {
|
|
func = args[0];
|
|
} else {
|
|
name = args[0];
|
|
func = args[1];
|
|
}
|
|
const realArgs = [name, executeAction.bind(this, func)];
|
|
if (name === undefined) {
|
|
realArgs.shift();
|
|
}
|
|
return action.apply(this, realArgs);
|
|
}
|
|
function runInWrappedAction(func) {
|
|
runInAction(() => {
|
|
executeAction.call(this, func);
|
|
});
|
|
}
|
|
|
|
// 不需要记录历史记录的时候直接使用原action
|
|
const unwrappedAction = action;
|
|
const runInUnwrappedAction = runInAction;
|
|
|
|
export {
|
|
go,
|
|
clearHistory,
|
|
wrappedAction,
|
|
runInWrappedAction,
|
|
unwrappedAction,
|
|
runInUnwrappedAction,
|
|
};
|