Skip to content

Instantly share code, notes, and snippets.

@yichaowang
Created March 23, 2015 03:59
Show Gist options
  • Save yichaowang/2c0cd2895555ae384597 to your computer and use it in GitHub Desktop.
Save yichaowang/2c0cd2895555ae384597 to your computer and use it in GitHub Desktop.
JS Bin Yichao Test // source http://jsbin.com/modasa
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="Yichao Test" />
<script src="http://cdnjs.cloudflare.com/ajax/libs/lodash.js/1.2.1/lodash.min.js"></script>
<meta charset=utf-8 />
<title>JS Bin</title>
</head>
<body>
<script id="jsbin-javascript">
var i = 0;
function Scope() {
this.$$watchers = [];
this.$$asyncQueue = [];
this.$$postDigestQueue = [];
this.$$phase = null;
}
Scope.prototype.$watch = function(watchFn, listenerFn, valueEq) {
var watcher = {
watchFn: watchFn,
listenerFn: listenerFn,
valueEq: !!valueEq
};
this.$$watchers.push(watcher);
};
Scope.prototype.$$digestOnce = function() {
var self = this;
var dirty;
_.forEach(this.$$watchers, function(watch) {
var newValue = watch.watchFn(self);
var oldValue = watch.last;
if (!self.$$areEqual(newValue, oldValue, watch.valueEq)) {
watch.listenerFn(newValue, oldValue, self);
dirty = true;
watch.last = (watch.valueEq ? _.cloneDeep(newValue) : newValue);
}
});
return dirty;
};
Scope.prototype.$beginPhase = function(phase) {
if (this.$$phase) {
throw this.$$phase + 'already in progress.';
}
this.$$phase = phase;
};
Scope.prototype.$clearPhase = function() {
this.$$phase = null;
};
Scope.prototype.$digest = function() {
var ttl = 10;
var dirty;
this.$beginPhase('$digest');
do {
while (this.$$asyncQueue.length) {
var asyncTask = this.$$asyncQueue.shift();
this.$eval(asyncTask.expression);
}
dirty = this.$$digestOnce();
if (dirty && !(ttl--)) {
this.$clearPhase();
throw "10 digest iterations reached";
}
} while (dirty);
this.$clearPhase();
while (this.$$postDigestQueue.length) {
this.$$postDigestQueue.shift()();
}
};
Scope.prototype.$$areEqual = function(newValue, oldValue, valueEq) {
if (valueEq) {
return _.isEqual(newValue, oldValue);
} else {
return newValue === oldValue ||
(typeof newValue === 'number' && typeof oldValue === 'number' &&
isNaN(newValue) && isNaN(oldValue));
}
};
Scope.prototype.$eval = function(expr, locals) {
return expr(this, locals);
};
Scope.prototype.$evalAsync = function(expr) {
var self = this;
if (!self.$$phase && !self.$$asyncQueue.legnth) {
setTimeout(function() {
if (self.$$asyncQueue.length) {
self.$digest();
}
}, 0);
}
this.$$asyncQueue.push({scope: this, expression: expr});
};
Scope.prototype.$apply = function(expr) {
try {
this.$beginPhase("$apply");
return this.$eval(expr);
} finally {
this.$clearPhase();
this.$digest();
}
};
Scope.prototype.$$postDigest = function(fn) {
this.$$postDigestQueue.push(fn);
};
var scope = new Scope();
scope.asyncEvaled = false;
scope.evaled = false;
scope.evalCounter = 0;
scope.asyncCounter = 0;
scope.$watch(
function(scope) {
return scope.evaled;
},
function(newValue, oldValue, scope) {
scope.evalCounter++;
}
);
scope.$eval(function(scope) {
scope.evaled = true;
});
console.log("Evaled: "+scope.evaled);
console.log("EvalCounte: "+scope.evalCounter);
scope.$evalAsync(function(scope) {
scope.asyncEvaled = true;
console.log("Evaled in asyncTask: "+scope.evalCounter);
});
setTimeout(function() {
console.log("Evaled after a while: "+scope.asyncEvaled);
console.log("EvalCounter after a while: "+scope.evalCounter);
});
</script>
<script id="jsbin-source-javascript" type="text/javascript">var i = 0;
function Scope() {
this.$$watchers = [];
this.$$asyncQueue = [];
this.$$postDigestQueue = [];
this.$$phase = null;
}
Scope.prototype.$watch = function(watchFn, listenerFn, valueEq) {
var watcher = {
watchFn: watchFn,
listenerFn: listenerFn,
valueEq: !!valueEq
};
this.$$watchers.push(watcher);
};
Scope.prototype.$$digestOnce = function() {
var self = this;
var dirty;
_.forEach(this.$$watchers, function(watch) {
var newValue = watch.watchFn(self);
var oldValue = watch.last;
if (!self.$$areEqual(newValue, oldValue, watch.valueEq)) {
watch.listenerFn(newValue, oldValue, self);
dirty = true;
watch.last = (watch.valueEq ? _.cloneDeep(newValue) : newValue);
}
});
return dirty;
};
Scope.prototype.$beginPhase = function(phase) {
if (this.$$phase) {
throw this.$$phase + 'already in progress.';
}
this.$$phase = phase;
};
Scope.prototype.$clearPhase = function() {
this.$$phase = null;
};
Scope.prototype.$digest = function() {
var ttl = 10;
var dirty;
this.$beginPhase('$digest');
do {
while (this.$$asyncQueue.length) {
var asyncTask = this.$$asyncQueue.shift();
this.$eval(asyncTask.expression);
}
dirty = this.$$digestOnce();
if (dirty && !(ttl--)) {
this.$clearPhase();
throw "10 digest iterations reached";
}
} while (dirty);
this.$clearPhase();
while (this.$$postDigestQueue.length) {
this.$$postDigestQueue.shift()();
}
};
Scope.prototype.$$areEqual = function(newValue, oldValue, valueEq) {
if (valueEq) {
return _.isEqual(newValue, oldValue);
} else {
return newValue === oldValue ||
(typeof newValue === 'number' && typeof oldValue === 'number' &&
isNaN(newValue) && isNaN(oldValue));
}
};
Scope.prototype.$eval = function(expr, locals) {
return expr(this, locals);
};
Scope.prototype.$evalAsync = function(expr) {
var self = this;
if (!self.$$phase && !self.$$asyncQueue.legnth) {
setTimeout(function() {
if (self.$$asyncQueue.length) {
self.$digest();
}
}, 0);
}
this.$$asyncQueue.push({scope: this, expression: expr});
};
Scope.prototype.$apply = function(expr) {
try {
this.$beginPhase("$apply");
return this.$eval(expr);
} finally {
this.$clearPhase();
this.$digest();
}
};
Scope.prototype.$$postDigest = function(fn) {
this.$$postDigestQueue.push(fn);
};
var scope = new Scope();
scope.asyncEvaled = false;
scope.evaled = false;
scope.evalCounter = 0;
scope.asyncCounter = 0;
scope.$watch(
function(scope) {
return scope.evaled;
},
function(newValue, oldValue, scope) {
scope.evalCounter++;
}
);
scope.$eval(function(scope) {
scope.evaled = true;
});
console.log("Evaled: "+scope.evaled);
console.log("EvalCounte: "+scope.evalCounter);
scope.$evalAsync(function(scope) {
scope.asyncEvaled = true;
console.log("Evaled in asyncTask: "+scope.evalCounter);
});
setTimeout(function() {
console.log("Evaled after a while: "+scope.asyncEvaled);
console.log("EvalCounter after a while: "+scope.evalCounter);
});
</script></body>
</html>
var i = 0;
function Scope() {
this.$$watchers = [];
this.$$asyncQueue = [];
this.$$postDigestQueue = [];
this.$$phase = null;
}
Scope.prototype.$watch = function(watchFn, listenerFn, valueEq) {
var watcher = {
watchFn: watchFn,
listenerFn: listenerFn,
valueEq: !!valueEq
};
this.$$watchers.push(watcher);
};
Scope.prototype.$$digestOnce = function() {
var self = this;
var dirty;
_.forEach(this.$$watchers, function(watch) {
var newValue = watch.watchFn(self);
var oldValue = watch.last;
if (!self.$$areEqual(newValue, oldValue, watch.valueEq)) {
watch.listenerFn(newValue, oldValue, self);
dirty = true;
watch.last = (watch.valueEq ? _.cloneDeep(newValue) : newValue);
}
});
return dirty;
};
Scope.prototype.$beginPhase = function(phase) {
if (this.$$phase) {
throw this.$$phase + 'already in progress.';
}
this.$$phase = phase;
};
Scope.prototype.$clearPhase = function() {
this.$$phase = null;
};
Scope.prototype.$digest = function() {
var ttl = 10;
var dirty;
this.$beginPhase('$digest');
do {
while (this.$$asyncQueue.length) {
var asyncTask = this.$$asyncQueue.shift();
this.$eval(asyncTask.expression);
}
dirty = this.$$digestOnce();
if (dirty && !(ttl--)) {
this.$clearPhase();
throw "10 digest iterations reached";
}
} while (dirty);
this.$clearPhase();
while (this.$$postDigestQueue.length) {
this.$$postDigestQueue.shift()();
}
};
Scope.prototype.$$areEqual = function(newValue, oldValue, valueEq) {
if (valueEq) {
return _.isEqual(newValue, oldValue);
} else {
return newValue === oldValue ||
(typeof newValue === 'number' && typeof oldValue === 'number' &&
isNaN(newValue) && isNaN(oldValue));
}
};
Scope.prototype.$eval = function(expr, locals) {
return expr(this, locals);
};
Scope.prototype.$evalAsync = function(expr) {
var self = this;
if (!self.$$phase && !self.$$asyncQueue.legnth) {
setTimeout(function() {
if (self.$$asyncQueue.length) {
self.$digest();
}
}, 0);
}
this.$$asyncQueue.push({scope: this, expression: expr});
};
Scope.prototype.$apply = function(expr) {
try {
this.$beginPhase("$apply");
return this.$eval(expr);
} finally {
this.$clearPhase();
this.$digest();
}
};
Scope.prototype.$$postDigest = function(fn) {
this.$$postDigestQueue.push(fn);
};
var scope = new Scope();
scope.asyncEvaled = false;
scope.evaled = false;
scope.evalCounter = 0;
scope.asyncCounter = 0;
scope.$watch(
function(scope) {
return scope.evaled;
},
function(newValue, oldValue, scope) {
scope.evalCounter++;
}
);
scope.$eval(function(scope) {
scope.evaled = true;
});
console.log("Evaled: "+scope.evaled);
console.log("EvalCounte: "+scope.evalCounter);
scope.$evalAsync(function(scope) {
scope.asyncEvaled = true;
console.log("Evaled in asyncTask: "+scope.evalCounter);
});
setTimeout(function() {
console.log("Evaled after a while: "+scope.asyncEvaled);
console.log("EvalCounter after a while: "+scope.evalCounter);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment