EventProxy使用學習筆記

介紹

EventProxy 僅僅是一個很輕量的工具,但是能夠帶來一種事件式編程的思維變化。有幾個特點:
• 利用事件機制解耦複雜業務邏輯
• 移除被廣爲詬病的深度callback嵌套問題
• 將串行等待變成並行等待,提升多異步協作場景下的執行效率
• 友好的Error handling
• 無平臺依賴,適合前後端,能用於瀏覽器和Node.js
• 兼容CMD,AMD以及CommonJS模塊環境

安裝

在頁面中嵌入腳本即可使用:

<script src="https://raw.github.com/JacksonTian/eventproxy/master/lib/eventproxy.js"></script>
    // EventProxy此時是一個全局變量
    var ep = new EventProxy();

API

通過事件實現異步協作是EventProxy的主要亮點。除此之外,它還是一個基本的事件庫。攜帶如下基本

• EventProxy

Examples:

var render = function (template, resources) {};
var proxy = new EventProxy();
proxy.all("template", "l10n", render);
proxy. emit ("template", template);
proxy. emit ("l10n", resources);

• on/addListener,綁定事件監聽器
• removeListener,移除事件的監聽器
• removeAllListeners,移除單個事件或者所有事件的監聽器
• emit,觸發事件
• once,綁定只執行一次的事件監聽器
• immediate,綁定事件,並立即觸發它,別名asap
• all,綁定一些事件,當所有事件執行後,將執行回調方法,別名assign
• fail,error事件處理
• tail,與all方法比較類似,都是註冊到事件組合上。不同在於,指定事件都觸發之後,如果事件依舊持續觸發,將會在每次觸發時調用handler,別名assignAll/assignAlways
• after,事件執行N次後,在執行回調函數
• any,事件執行完成後,只執行一次回調函數
• not,當事件名稱與綁定的綁定事件名稱不符時,才執行回調函數
• done,error事件處理
• create,創建EventProxy

Examples:

var ep = EventProxy.create();//等價於var ep = new EventProxy();
ep.all('user', 'articles', function(user, articles) {
  // do something...
});
// or one line ways: Create EventProxy and Assign
var ep = EventProxy.create('user', 'articles', function(user, articles) {
  // do something...
});

爲了照顧各個環境的開發者,上面的方法多具有別名。
• YUI3使用者,subscribe對應的是on/addlistener,fire對應的是emit。
• jQuery使用者,trigger對應的是emit,bind對應的是on/addlistener。
• removeListener和removeAllListeners可以通過別名unbind完成。

異步協作

多類型異步協作

此處以頁面渲染爲場景,渲染頁面需要模板、數據。假設都需要異步讀取。

var ep = new EventProxy();
ep.all('tpl', 'data', function (tpl, data) {
  // 在所有指定的事件觸發後,將會被調用執行
  // 參數對應各自的事件名
});
fs.readFile('template.tpl', 'utf-8', function (err, content) {
  ep.emit('tpl', content);
});
db.get('some sql', function (err, result) {
  ep.emit('data', result);
});

all方法將handler註冊到事件組合上。當註冊的多個事件都觸發後,將會調用handler執行,每個事件傳遞的數據,將會依照事件名順序,傳入handler作爲參數。

重複異步協作

此處以讀取目錄下的所有文件爲例,在異步操作中,我們需要在所有異步調用結束後,執行某些操作。

var ep = new EventProxy();
ep.after('got_file', files.length, function (list) {
  // 在所有文件的異步執行結束後將被執行
  // 所有文件的內容都存在list數組中
});
for (var i = 0; i < files.length; i++) {
  fs.readFile(files[i], 'utf-8', function (err, content) {
    // 觸發結果事件
    ep.emit('got_file', content);
  });
}

after方法適合重複的操作,比如讀取10個文件,調用5次數據庫等。將handler註冊到N次相同事件的觸發上。達到指定的觸發數,handler將會被調用執行,每次觸發的數據,將會按觸發順序,存爲數組作爲參數傳入。

持續型異步協作

此處以股票爲例,數據和模板都是異步獲取,但是數據會是刷新,視圖會重新刷新。

var ep = new EventProxy();
ep.tail('tpl', 'data', function (tpl, data) {
  // 在所有指定的事件觸發後,將會被調用執行
  // 參數對應各自的事件名的最新數據
});
fs.readFile('template.tpl', 'utf-8', function (err, content) {
  ep.emit('tpl', content);
});
setInterval(function () {
  db.get('some sql', function (err, result) {
    ep.emit('data', result);
  });
}, 2000);

tailall方法比較類似,都是註冊到事件組合上。不同在於,指定事件都觸發之後,如果事件依舊持續觸發,將會在每次觸發時調用handler,極像一條尾巴。

異常處理

在異步方法中,實際上,異常處理需要佔用一定比例的精力。在過去一段時間內,我們都是通過額外添加error事件來進行處理的,代碼大致如下:

exports.getContent = function (callback) {
 var ep = new EventProxy();
  ep.all('tpl', 'data', function (tpl, data) {
    // 成功回調
    callback(null, {
      template: tpl,
      data: data
    });
  });
  // 偵聽error事件
  ep.bind('error', function (err) {
    // 卸載掉所有handler
    ep.unbind();
    // 異常回調
    callback(err);
  });
  fs.readFile('template.tpl', 'utf-8', function (err, content) {
    if (err) {
      // 一旦發生異常,一律交給error事件的handler處理
      return ep.emit('error', err);
    }
    ep.emit('tpl', content);
  });
  db.get('some sql', function (err, result) {
    if (err) {
      // 一旦發生異常,一律交給error事件的handler處理
      return ep.emit('error', err);
    }
    ep.emit('data', result);
  });
};

EventProxy經過很多實踐後,提供了優化的錯誤處理方案:

exports.getContent = function (callback) {
 var ep = new EventProxy();
  ep.all('tpl', 'data', function (tpl, data) {
    // 成功回調
    callback(null, {
      template: tpl,
      data: data
    });
  });
  // 添加error handler
  ep.fail(callback);

  fs.readFile('template.tpl', 'utf-8', ep.done('tpl'));
  db.get('some sql', ep.done('data'));
};

上述代碼優化之後,開發者幾乎不用關心異常處理。上述代碼的轉換,祕訣在fail方法和done方法中。

神奇的fail

ep.fail(callback);
// 由於參數位相同,它實際是
ep.fail(function (err) {
  callback(err);
});
// 等價於
ep.bind('error', function (err) {
  // 卸載掉所有handler
  ep.unbind();
  // 異常回調
  callback(err);
});
fail方法偵聽了error事件,默認處理卸載掉所有handler,並調用回調函數。
神奇的done
ep.done('tpl');
// 等價於
function (err, content) {
  if (err) {
    // 一旦發生異常,一律交給error事件的handler處理
    return ep.emit('error', err);
  }
  ep.emit('tpl', content);
}

在Node的最佳實踐中,回調函數第一個參數一定會是一個error對象。檢測到異常後,將會觸發error事件。剩下的參數,將觸發事件,傳遞給對應handler處理。

done也接受回調函數

done方法除了接受事件名外,還接受回調函數。如果是函數時,它將剔除第一個error對象(此時爲null)後剩餘的參數,傳遞給該回調函數作爲參數。該回調函數無需考慮異常處理。

ep.done(function (content) {
  // 這裏無需考慮異常
});

本文轉自:百度文庫

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章