cocos2dx-js CCBoot.js異步池cc.AsyncPool淺析

       首先通過一個問題的出現以及解決,來介紹cc.AsyncPool的實現。
       假設現在有個需求,就是一個頁面裏面要顯示很多圖片,而且這些圖片是需要下載的。如果我們的實現方法是顯示這個頁面的時候,一次性請求並創建這些圖片,這樣做可能會出現當我們要顯示這個頁面的時候,會出現卡了幾秒,然後圖片一次性顯示出來,顯然這種體驗是很差的。所以我們可能優化一下,當要顯示這個頁面時候先顯示背景,然後創建去請求一個圖片並創建成功後再去處理下一個。這裏的實現模式就用cc.AsyncPool異步池來實現。
       通過上面的問題,我們先思考一下,我們實現的功能就是,別人傳一堆數據過來,我們先取出一個數據,然後交給迭代器且處理,同時迭代器在處理完成的時候通知給我們,在通知給我們的時候,我們繼續去下一個數據,當迭代器處理完成的數據等於原先總的數據的時候,就說明處理完成了。

所以我們實現一個異步池需要一下參數
      1、迭代處理的對象srcObj(上面例子的所有圖片的遠程地址列表)
      2、並行限制 limit,就是一次可以同時處理數量
      3、迭代器(上面例子的單個圖片下載和創建控件流程)
      4、全部處理後的回調 onEnd
      5、上下文target(js的語法,修改函數的this指向)

      下面是cc.AsyncPool帶註釋的代碼。

//+++++++++++++++++++++++++something about async begin+++++++++++++++++++++++++++++++
/**
 * Async Pool class, a helper of cc.async
 * @param {Object|Array} srcObj 迭代對象
 * @param {Number} limit the limit of parallel(並行) number  並行限制
 * @param {function} iterator 迭代器
 * @param {function} onEnd 全部執行後的回調
 * @param {object} target 迭代的上下文
 * @constructor
 */
// async 異步
// 異步池大概流程: 
// 記錄總的需要處理的數量
// 取出一個數據,當前工作的數量加1,並執行迭代器 
//迭代器執行結束後,當前工作的數量減1,已完成的數據加1
// 如果已完成的數量等於需要處理的數據,表明全部處理完成,反之表面還沒全部處理結束,嘗試處理下一個數據
// 處理下一個數據時,如果當前工作的數據沒有超過最大併發數,且待處理的池還有數據,取下個數據處理
  
cc.AsyncPool = function (srcObj, limit, iterator, onEnd, target) {
    var self = this;
    // 是否執行後全部結束的回調
    self._finished = false;
    // 需要處理的數據
    self._srcObj = srcObj;
   // 同時併發的最大數量
    self._limit = limit;
    // 等待處理的數據池
    self._pool = [];
    self._iterator = iterator;
    self._iteratorTarget = target;
    self._onEnd = onEnd;
    self._onEndTarget = target;
    self._results = srcObj instanceof Array ? [] : {};
    self._errors = srcObj instanceof Array ? [] : {};

    // 把srcObj已index-value的元素壓入到數組_pool
    cc.each(srcObj, function (value, index) {
        self._pool.push({index: index, value: value});
    });

    // 總的數量
    self.size = self._pool.length;
    // 已經處理完成的數量,用於處理一個結束後判斷是否全部處理完成用
    self.finishedSize = 0;
    // 正在工作的數量
    self._workingSize = 0;

    self._limit = self._limit || self.size;

    // 注入迭代器和其上下文
    self.onIterator = function (iterator, target) {
        self._iterator = iterator;
        self._iteratorTarget = target;
    };

    // 注入結束回調和其上下文(這個是不是沒有用,和下面的onEnd衝突?)
    self.onEnd = function (endCb, endCbTarget) {
        self._onEnd = endCb;
        self._onEndTarget = endCbTarget;
    };

    // 處理單個
    self._handleItem = function () {
        var self = this;
        // 待處理池爲空或者 當前工作的數量已經達到限制
        if (self._pool.length === 0 || self._workingSize >= self._limit)
            return;                                                         
        // 移除出一個
        var item = self._pool.shift();
        var value = item.value, index = item.index;
        // 正在處理的數量加1
        self._workingSize++;
        // 運行迭代器,參數爲value,key,單個回調函數,異步池對象
        self._iterator.call(self._iteratorTarget, value, index,
            // 單個處理接口回調函數,參數爲err和接口
            function (err, result) {
                // 結束回調已經執行過
                if (self._finished) {
                    return;
                }

                // 記錄每個數據處理的錯誤或者結果
                if (err) {
                    self._errors[this.index] = err;
                }
                else {
                    self._results[this.index] = result;
                }
                // 已完成數量加1
                self.finishedSize++;
                // 正在運行數量減1
                self._workingSize--;
                // 完成數量等於總的數量(這裏可以去掉這個變量)
                // 可以用當前正在工作的爲空,且異步池沒有對象了
                // if (self._workingSize === 0 && self._pool.length === 0)
                if (self.finishedSize === self.size) {
                    var errors = self._errors.length === 0 ? null : self._errors;
                    self.onEnd(errors, self._results);
                    return;
                }
                // 處理完一個後,處理下一個
                self._handleItem();
            }.bind(item),
            self);
    };
	
    // 異步池創建成功後,調用這個開始處理數據
    self.flow = function () {
        var self = this;
        if (self._pool.length === 0) {
            if (self._onEnd)
                self._onEnd.call(self._onEndTarget, null, []);
            return;
        }
        // 一次性並行多個
        for (var i = 0; i < self._limit; i++)
            self._handleItem();
    };
 
    // 全部處理完成回調
    self.onEnd = function(errors, results) {
        self._finished = true;
        if (self._onEnd) {
            var selector = self._onEnd;
            var target = self._onEndTarget;
            // 清空引用
            self._onEnd = null;
            self._onEndTarget = null;
            selector.call(target, errors, results);
        }
    };
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章