$evalAsync是什么
顧名思義,延遲執(zhí)行一段作用于相應(yīng)scope的eval代碼乔妈。于timeout的區(qū)別是揭朝,timeout會(huì)把代碼交給瀏覽器去執(zhí)行,開(kāi)發(fā)者無(wú)法控制到底什么時(shí)候執(zhí)行降铸。$evalAsync運(yùn)行代碼是在digest周期內(nèi)運(yùn)行的。具體可以通過(guò)這個(gè)測(cè)試案例看的很明白摇零。
it('$evalAsync', function() {
scope.aValue = 123;
scope.asyncEvaluated = false;
scope.asyncEvaluatedImmediately = false;
var watchFn = function(scope){
return scope.aValue;
}
var listenFn = function(newvalue,oldvalue,scope){
scope.$evalAsync(function(scope){
scope.asyncEvaluated = true;//隨后執(zhí)行的
})
scope.asyncEvaluatedImmediately = scope.asyncEvaluated;//立即執(zhí)行的推掸,這時(shí)候應(yīng)該是false
}
scope.$watch(watchFn,listenFn);
scope.$digest();
expect(scope.asyncEvaluated).toBe(true);
expect(scope.asyncEvaluatedImmediately).toBe(false);
});
實(shí)現(xiàn)思路
首先在scope里面創(chuàng)建一個(gè)延遲eval隊(duì)列。
function Scope() {
this.$$watchers = [];
this.$$lastDirtyWatch = null;
this.$$asyncQueue = [];
}
調(diào)用$evalAsync的時(shí)候就把要執(zhí)行的函數(shù)推入這個(gè)隊(duì)列驻仅。
Scope.prototype.$evalAsync = function (expr) {
this.$$asyncQueue.push({ scope: this, expression: expr });
}
在每次digest之前都把這個(gè)隊(duì)列里的函數(shù)用當(dāng)前scope執(zhí)行一下
Scope.prototype.$digest = function () {
var dirty;
var ttl = 10;
do {
while (this.$$asyncQueue.length) {
var asyncTask = this.$$asyncQueue.shift();
asyncTask.scope.$eval(asyncTask.expression);
}
dirty = this.$$digestOnce();
if (dirty && !(ttl--)) {
throw "digest次數(shù)到達(dá)上限依然不穩(wěn)定"
}
} while (dirty);
}
為什么這個(gè)while循環(huán)放在了digestOnce的前面谅畅?
注意的是,這里的while循環(huán)放到了$$digestOnce方法的前面噪服,需要解釋一下為什么放到了前面:
第一次執(zhí)行這個(gè)digest的時(shí)候毡泻,是初始化的時(shí)候,值肯定是臟的粘优,這時(shí)候$$asyncQueue里面是沒(méi)有東西的仇味,所以直接運(yùn)行$$digestOnce,運(yùn)行$$digestOnce的時(shí)候敬飒,才會(huì)執(zhí)行watcher里面的listenFn邪铲,也就是這時(shí)候才會(huì)把a(bǔ)syncEval注冊(cè)的方法推入隊(duì)列,然后scope.asyncEvaluatedImmediately = scope.asyncEvaluated;
這段代碼會(huì)運(yùn)行无拗,當(dāng)然是false的带到。
運(yùn)行完了以后,跳出digestOnce,因?yàn)閘instenFn被運(yùn)行了揽惹,所以肯定返回的是dirty被饿,那么就會(huì)進(jìn)行下一次循環(huán),在這次新的循環(huán)里搪搏,再去運(yùn)行async隊(duì)列里面的函數(shù)狭握。
如果放在digestOnce后面會(huì)怎么樣?
詳情可以看自己錄的自言自語(yǔ)的視頻疯溺。