|
|
|
@ -1,5 +1,72 @@
|
|
|
|
|
import { _ } from "@/core"; |
|
|
|
|
|
|
|
|
|
let uid = 0; |
|
|
|
|
|
|
|
|
|
const pendingCleanupDeps = []; |
|
|
|
|
|
|
|
|
|
const cleanupDeps = () => { |
|
|
|
|
for (let i = 0; i < pendingCleanupDeps.length; i++) { |
|
|
|
|
const dep = pendingCleanupDeps[i]; |
|
|
|
|
dep.subs = dep.subs.filter(s => s); |
|
|
|
|
dep._pending = false; |
|
|
|
|
} |
|
|
|
|
pendingCleanupDeps.length = 0; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* A dep is an observable that can have multiple |
|
|
|
|
* directives subscribing to it. |
|
|
|
|
*/ |
|
|
|
|
class Dep { |
|
|
|
|
constructor() { |
|
|
|
|
this.id = uid++; |
|
|
|
|
this._pending = false; |
|
|
|
|
this.subs = []; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
addSub(sub) { |
|
|
|
|
this.subs.push(sub); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
removeSub(sub) { |
|
|
|
|
this.subs[this.subs.indexOf(sub)] = null; |
|
|
|
|
if (!this._pending) { |
|
|
|
|
this._pending = true; |
|
|
|
|
pendingCleanupDeps.push(this); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
depend() { |
|
|
|
|
if (Dep.target) { |
|
|
|
|
Dep.target.addDep(this); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
notify(options) { |
|
|
|
|
// stabilize the subscriber list first
|
|
|
|
|
const subs = this.subs.filter(s => s); |
|
|
|
|
for (let i = 0, l = subs.length; i < l; i++) { |
|
|
|
|
subs[i].update(options); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// the current target watcher being evaluated.
|
|
|
|
|
// this is globally unique because there could be only one
|
|
|
|
|
// watcher being evaluated at any time.
|
|
|
|
|
Dep.target = null; |
|
|
|
|
const targetStack = []; |
|
|
|
|
|
|
|
|
|
function pushTarget(_target) { |
|
|
|
|
if (Dep.target) targetStack.push(Dep.target); |
|
|
|
|
Dep.target = _target; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function popTarget() { |
|
|
|
|
Dep.target = targetStack.pop(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function noop(a, b, c) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -7,6 +74,7 @@ function isNative(Ctor) {
|
|
|
|
|
return typeof Ctor === "function" && /native code/.test(Ctor.toString()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const hasProto = "__proto__" in {}; |
|
|
|
|
|
|
|
|
|
const _toString = Object.prototype.toString; |
|
|
|
@ -152,56 +220,6 @@ const $$skipArray = {
|
|
|
|
|
$vbsetter: falsy |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
let uid = 0; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* A dep is an observable that can have multiple |
|
|
|
|
* directives subscribing to it. |
|
|
|
|
*/ |
|
|
|
|
class Dep { |
|
|
|
|
constructor() { |
|
|
|
|
this.id = uid++; |
|
|
|
|
this.subs = new Set(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
addSub(sub) { |
|
|
|
|
this.subs.add(sub); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
removeSub(sub) { |
|
|
|
|
this.subs.delete(sub); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
depend() { |
|
|
|
|
if (Dep.target) { |
|
|
|
|
Dep.target.addDep(this); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
notify(options) { |
|
|
|
|
// stabilize the subscriber list first
|
|
|
|
|
const subs = [...this.subs.values()]; |
|
|
|
|
for (let i = 0, l = subs.length; i < l; i++) { |
|
|
|
|
subs[i].update(options); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// the current target watcher being evaluated.
|
|
|
|
|
// this is globally unique because there could be only one
|
|
|
|
|
// watcher being evaluated at any time.
|
|
|
|
|
Dep.target = null; |
|
|
|
|
const targetStack = []; |
|
|
|
|
|
|
|
|
|
function pushTarget(_target) { |
|
|
|
|
if (Dep.target) targetStack.push(Dep.target); |
|
|
|
|
Dep.target = _target; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function popTarget() { |
|
|
|
|
Dep.target = targetStack.pop(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//如果浏览器不支持ecma262v5的Object.defineProperties或者存在BUG,比如IE8
|
|
|
|
|
//标准浏览器使用__defineGetter__, __defineSetter__实现
|
|
|
|
|
let canHideProperty = true; |
|
|
|
@ -286,6 +304,7 @@ function flushSchedulerQueue() {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
resetSchedulerState(); |
|
|
|
|
cleanupDeps(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -853,7 +872,7 @@ function watch(model, expOrFn, cb, options) {
|
|
|
|
|
options = options || {}; |
|
|
|
|
options.user = true; |
|
|
|
|
let exps; |
|
|
|
|
if (_.isFunction(expOrFn) || !(exps = expOrFn.match(/[a-zA-Z0-9BI._.*]+|[|][|]|[&][&]|[(]|[)]/g)) || (exps.length === 1 && expOrFn.indexOf("*") < 0)) { |
|
|
|
|
if (_.isFunction(expOrFn) || !(exps = expOrFn.match(/[a-zA-Z0-9_.*]+|[|][|]|[&][&]|[(]|[)]/g)) || (exps.length === 1 && expOrFn.indexOf("*") < 0)) { |
|
|
|
|
const watcher = new Watcher(model, expOrFn, cb, options); |
|
|
|
|
if (options.immediate) { |
|
|
|
|
cb(watcher.value); |
|
|
|
@ -1420,32 +1439,9 @@ export const Fix = {
|
|
|
|
|
freeze, |
|
|
|
|
del, |
|
|
|
|
Watcher, |
|
|
|
|
cleanupDeps, |
|
|
|
|
pushTarget, |
|
|
|
|
popTarget, |
|
|
|
|
watch, |
|
|
|
|
toJSON |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
window.testT = function (count = 5000) { |
|
|
|
|
const subsArray = []; |
|
|
|
|
|
|
|
|
|
const subsSet = new Set(); |
|
|
|
|
|
|
|
|
|
for (let i = 0; i < count; i++) { |
|
|
|
|
subsArray.push("" + i); |
|
|
|
|
subsSet.add("" + i); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
console.time("array"); |
|
|
|
|
for (let i = count; i >= 0; i--) { |
|
|
|
|
remove(subsArray, "" + 1); |
|
|
|
|
} |
|
|
|
|
console.timeEnd("array"); |
|
|
|
|
|
|
|
|
|
console.time("set"); |
|
|
|
|
for (let i = count; i >= 0; i--) { |
|
|
|
|
subsSet.delete("" + 1); |
|
|
|
|
} |
|
|
|
|
console.timeEnd("set"); |
|
|
|
|
}; |
|
|
|
|