国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

angular的ViewModel設(shè)計

int64 / 2918人閱讀

摘要:換言之,的對應(yīng)的,此外它還有。它們共同構(gòu)成的監(jiān)控系統(tǒng)。和是相輔相成的。兩者一起,構(gòu)成了作用域的核心功能數(shù)據(jù)變化的響應(yīng)。迭代的最大值稱為。框架設(shè)計第三版,敬請期待

angular的ViewModel有一個專門的官方術(shù)語叫$scope, 它只是一個普通構(gòu)造器(Scope)的實例。換言之,它是一個普通的JS對象。為了實現(xiàn)MVVM框架通常宣傳的那種“改變數(shù)據(jù)即改變視圖”的魔幻效果,它得裝備上更多更強大的外掛。

名:
姓:

姓名: {{firstName + " " + lastName}}

app.controller會產(chǎn)生一個$scope對象, 這個$scope是傳進去的。相當(dāng)于:

var $scope = new Scope();
$scope.firstName = "Jane";
$scope.lastName = "Smith";

相對于avalon將所有vm扁平化地放到avalon.vmodels中,angular則傾向?qū)?b>$scope對象以樹的形式組織起來。

function Scope() {
this.$id = nextUid();
      this.$$phase = this.$parent = this.$$watchers =
                     this.$$nextSibling = this.$$prevSibling =
                     this.$$childHead = this.$$childTail = null;
      this.$root = this;
      this.$$destroyed = false;
      this.$$listeners = {};
      this.$$listenerCount = {};
      this.$$watchersCount = 0;
      this.$$isolateBindings = null;
}

其中$parent$$nextSibling, $$prevSibling, $$childHead, $$childTail,$root是指向其他$scope對象。 $$watchers是綁定對象的訂閱數(shù)組,$$watchersCount是其長度, $$listeners 是放手動觸發(fā)的函數(shù),$$listenerCount是其長度。

由于angular是一個普通的JS對象,當(dāng)屬性發(fā)生變化時,它本身不可能像avalon那么靈敏地跑去$fire。 于是它實現(xiàn)了一套復(fù)雜的$fire方法,但它不叫$fire, 叫做$digest

換言之,avalon的$watch對應(yīng)angular的$watch,此外它還有$watchGroup, $watchCollection。avalon的$fire方法對應(yīng)angular的$digest, 為了安全,它外面還有$applyAsync$apply, $evalAsync等幾個殼函數(shù)。它們共同構(gòu)成angular的監(jiān)控系統(tǒng)。$watch$digest是相輔相成的。兩者一起,構(gòu)成了angular作用域的核心功能:數(shù)據(jù)變化的響應(yīng)。

先看$watch方法, 傳參比avalon復(fù)雜多,但結(jié)果都是返回一個移除監(jiān)聽的函數(shù):

Scope.prototype.$watch: function(watchExp, listener, objectEquality, prettyPrintExpression) {
  //將表達(dá)式轉(zhuǎn)換為求值函數(shù)
    var get = $parse(watchExp); 

    if (get.$$watchDelegate) {
      return get.$$watchDelegate(this, listener, objectEquality, get, watchExp);
    }
    
    var scope = this,
    //所有綁定對象都放在一個數(shù)組中,因此存在性能問題
        array = scope.$$watchers,
    //構(gòu)建綁定對象
        watcher = {
          fn: listener,//刷新函數(shù)
          last: initWatchVal,//舊值
          get: get,//求值函數(shù)
          exp: prettyPrintExpression || watchExp,//表達(dá)式
          eq: !!objectEquality// 比較方法
        };

    lastDirtyWatch = null;

    if (!isFunction(listener)) {
      watcher.fn = noop;
    }

    if (!array) {
      array = scope.$$watchers = [];
    }
    array.unshift(watcher);
    incrementWatchersCount(this, 1);

    return function deregisterWatch() {//移除綁定對象
      if (arrayRemove(array, watcher) >= 0) {
        incrementWatchersCount(scope, -1);
      }
      lastDirtyWatch = null;
    };
},

而$digest則復(fù)雜多了,我們先實現(xiàn)它的一個簡化版,遍歷其所有綁定對象,執(zhí)行其刷新函數(shù)。

Scope.prototype.$digest = function() {
  var list = this.$$watchers || []
  list.forEach(function(watch) {
    var newValue = watch.get()
    var oldValue = watch.last;
    if (newValue !== oldValue) {
      watch.fn(newValue, oldValue, self);
    }
    watch.last = newValue;
  })
}

到目前為止,它的邏輯與 avalon的一樣,但要明白一點,avalon的監(jiān)控是智能的,如果更新A屬性,導(dǎo)致了B屬性也發(fā)生變化,那么avalon也連忙更新B涉及的視圖。而angular的$$watcher 里面都是一個個普通對象,假如里面有A,B兩個對象。先執(zhí)行A,A值沒有變化,再執(zhí)行B,B變化了,但B在變化時的同時,也修改了A值。但這時,循環(huán)已經(jīng)完畢。B涉及的視圖變動 ,A沒有變動,這就不合理了。因此,我們需要在某個綁定對象發(fā)生了一次改動后,再重新檢測這個數(shù)組。

我們把現(xiàn)在的$digest函數(shù)改名為$$digestOnce,它把所有的監(jiān)聽器運行一次,返回一個布爾值,表示是否還有變更了:

Scope.prototype.$$digestOnce = function() {
  var self  = this;
  var dirty;
  _.forEach(this.$$watchers, function(watch) {
    var newValue = watch.get();
    var oldValue = watch.last;
    if (newValue !== oldValue) {
      watch.fn(newValue, oldValue, self);
      dirty = true;
    }
    watch.last = newValue;
  });
  return dirty;
};

然后,我們重新定義$digest,它作為一個“外層循環(huán)”來運行,當(dāng)有變更發(fā)生的時候,調(diào)用$$digestOnce

Scope.prototype.$digest = function() {
  var dirty;
  do {
    dirty = this.$$digestOnce();
  } while (dirty);
};

$digest現(xiàn)在至少運行每個監(jiān)聽器一次了。如果第一次運行完,有監(jiān)控值發(fā)生變更了,標(biāo)記為dirty,所有監(jiān)聽器再運行第二次。這會一直運行,直到所有監(jiān)控的值都不再變化,整個局面穩(wěn)定下來了。

但這里面有一個風(fēng)險,比如A的求值函數(shù)里會修改B, B的求值函數(shù)又修改A,那么大家都無法穩(wěn)定下來,不斷死循環(huán)。因此我們得把digest的運行控制在一個可接受的迭代數(shù)量內(nèi)。如果這么多次之后,作用域還在變更,就勇敢放手,宣布它永遠(yuǎn)不會穩(wěn)定。在這個點上,我們會拋出一個異常,因為不管作用域的狀態(tài)變成怎樣,它都不太可能是用戶想要的結(jié)果。

迭代的最大值稱為TTL(short for Time To Live)。這個值默認(rèn)是10,可能有點小(我們剛運行了這個digest 成千上萬次),但是記住這是一個性能敏感的地方,因為digest經(jīng)常被執(zhí)行,而且每個digest運行了所有的監(jiān)聽器。

Scope.prototype.$digest = function() {
  var ttl = 10;
  var dirty;
  do {
    dirty = this.$$digestOnce();
    if (dirty && !(ttl--)) {
      throw "10 digest iterations reached";
    }
  } while (dirty);
};

但這只是模擬了angular的$digest的冰山一角,可見沒有訪問器屬性這高階魔法,想實現(xiàn)MVVM是非常麻煩與復(fù)雜,并且用戶使用起來也別扭。

有關(guān)$digest的源碼與解決可見這里

https://github.com/angular/an...

http://www.cnblogs.com/xuezhi...

我們再看$digest 是怎么與angular的ng-model 關(guān)聯(lián)在一起。

ng-model指令有一個$post方法,它在里面進行綁定事件,如果用戶提供了updateOn這個選項,選項是一些事件名,那么它就為元素綁定對應(yīng)的事件,否則就綁定blur方法

post: function ngModelPostLink(scope, element, attr, ctrls) {
  var modelCtrl = ctrls[0];
  if (modelCtrl.$options.getOption("updateOn")) {
    element.on(modelCtrl.$options.getOption("updateOn"), function(ev) {
      modelCtrl.$$debounceViewValueCommit(ev && ev.type);
    });
  }
  function setTouched() {
    modelCtrl.$setTouched();
  }
  element.on("blur", function() {
    if (modelCtrl.$touched) return;

    if ($rootScope.$$phase) {
      scope.$evalAsync(setTouched);
    } else {
      scope.$apply(setTouched);
    }
  });
}

我們先看blur的回調(diào),里面$evalAsync$apply方法,它們里面就會調(diào)用$digest,進行臟檢測。

$evalAsync: function(expr, locals) {
  if (!$rootScope.$$phase && !asyncQueue.length) {
    $browser.defer(function() {
      if (asyncQueue.length) {
        $rootScope.$digest();
      }
    });
  }

 //...略
},
$apply: function(expr) {
  try {
    beginPhase("$apply");
    //...略
  } finally {
    try {
      $rootScope.$digest();
    } catch (e) {
      $exceptionHandler(e);
      throw e;
    }
  }
},

再看$$debounceViewValueCommit方法,里面也有一個$apply方法。換言之,殊途同歸,全部匯在$digest里面處理。

但如果許多地方同時發(fā)生改變,會不會將它搞死呢?不會,我們留意一下$digest的源碼最上方有一句 beginPhase("$digest"),臨結(jié)束時也有一句clearPhase()$apply 里面也是 beginPhase("$apply")clearPhase(),它們標(biāo)識這個$scope對象進行臟檢測,直接拋錯。

function beginPhase(phase) {
     if ($rootScope.$$phase) {
       throw $rootScopeMinErr("inprog", "{0} already in progress", $rootScope.$$phase);
     }

     $rootScope.$$phase = phase;
}

 function clearPhase() {
   $rootScope.$$phase = null;
 }

$apply會將錯誤catch住,不讓它影響程序繼續(xù)運行。這就是官方推我們使用$apply驅(qū)動程序運行,而不直接用$digest的緣故。

通過上面的分析,avalon與angular的設(shè)計重點是不同的,avalon是忙于發(fā)掘語言特征,通過訪問器中的setter與getter將其那個簡單的觀察者模式放進去。angular則忙于構(gòu)建其復(fù)雜無比的觀察者模式(本節(jié)沒有展現(xiàn)其全貌,它除了$$watchers隊列,還有asyncQueue隊列,postDigestQueue隊列,applyAsyncQueue隊列), 并且為了diff新舊值的不同,發(fā)展出一套名叫臟檢測的機制。

from 《javascript框架設(shè)計》第三版,敬請期待

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/87933.html

相關(guān)文章

  • 【教學(xué)向】150行代碼教你實現(xiàn)一個低配版MVVM庫(2)- 代碼篇

    摘要:也放出地址,上面有完整工程以及在線演示地址相關(guān)閱讀教學(xué)向行代碼教你實現(xiàn)一個低配版的庫原理篇教學(xué)向行代碼教你實現(xiàn)一個低配版的庫代碼篇教學(xué)向再加行代碼教你實現(xiàn)一個低配版的庫設(shè)計篇教學(xué)向再加行代碼教你實現(xiàn)一個低配版的庫原理篇 書接上一篇: 150行代碼教你實現(xiàn)一個低配版的MVVM庫(1)- 原理篇 寫在前面 為了便于分模塊,和閱讀,我使用了Typescript來進行coding,總行數(shù)是正好...

    loonggg 評論0 收藏0
  • MVC MVP MVVM

    摘要:,的事件回調(diào)函數(shù)中調(diào)用的操作方法。以為例調(diào)用關(guān)系模式實際就是將中的改名為,調(diào)用過程基本一致,最大的改良是間的雙向綁定。和間,有一個對象,可以操作修改,使用。 參考:MVC,MVP 和 MVVM 的圖示 - 阮一峰http://www.ruanyifeng.com/blo...Web開發(fā)的MVVM模式http://www.cnblogs.com/dxy198...界面之下:還原真實的MV...

    wushuiyong 評論0 收藏0
  • MVC MVP MVVM

    摘要:,的事件回調(diào)函數(shù)中調(diào)用的操作方法。以為例調(diào)用關(guān)系模式實際就是將中的改名為,調(diào)用過程基本一致,最大的改良是間的雙向綁定。和間,有一個對象,可以操作修改,使用。 參考:MVC,MVP 和 MVVM 的圖示 - 阮一峰http://www.ruanyifeng.com/blo...Web開發(fā)的MVVM模式http://www.cnblogs.com/dxy198...界面之下:還原真實的MV...

    Tangpj 評論0 收藏0
  • vue簡單入門(一)vue是什么,為什么我們要學(xué)vue?

    摘要:是什么為什么我們要使用說到了,我們就不得不先聊一下是什么以及為什么我們要使用,他能給我們的開發(fā)帶來什么樣的便利呢首先,我們來看一下的自我介紹讀音,類似于是一套用于構(gòu)建用戶界面的漸進式框架。 作為一個剛?cè)胄胁痪玫牟锁B不知從什么時候開始就有了寫一個自己的專欄的想法,剛好今天沒事就給自己挖一個坑,分享一下我對vue的見解和一些領(lǐng)悟,整個專欄應(yīng)該會包括vue,vue-cli,vue-route...

    Lucky_Boy 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<