Koa中介軟體方式實現API的Undo功能,koa中介軟體apiundo

來源:互聯網
上載者:User

Koa中介軟體方式實現API的Undo功能,koa中介軟體apiundo
Koa中介軟體方式實現API的Undo功能API的Undo功能

使用過Gmail或者163郵箱的同學會經常看到,當對郵件進行一些操作時會出現一個類似Toast的提示(大致意思是:操作已經完成,是否撤銷)如所示:

當點擊撤銷時,之前執行的操作能夠被還原,這種設計對於使用者的誤操作是一個非常棒的補救方案。

之前聽過一句有關互動設計的話說的非常好,不要在使用者每做一步操作時彈出Alert讓使用者選擇”確定”或者”取消”,更好的做法是執行操作,然後讓使用者能夠Undo。

實現API Undo的方案

其實Undo是很老的技術,在編輯器中無處不在,只是在API設計中使用的還比較少。最近一直在使用Node開發,因此想使用Node實現一下API的Undo。

首先要明確幾點:

  • 並不是所有的API都需要Undo,比如擷取資料的介面就完全沒有Undo的必要(而且邏輯上也沒辦法做)
  • 只能針對使用者最後一次操作進行Undo
  • Undo是在使用者維度,使用者不能Undo其他使用者的操作
傳統方案(Plan A):
  • 需要對所有需要Undo的介面提供Undo邏輯;
  • 當使用者要Undo最近一次操作時需要調用這個方法(常常會涉及資料庫操作)。
新方案(Plan B):
  • 以中介軟體(類似Java中的攔截器)方式提供Undo服務
  • 對需要Undo的API邏輯放入指定隊列順延強制
  • 調用Undo介面時將最近一次操作從順延強制的隊列中移除
  • 調用其他介面是立即執行延遲隊列中的邏輯
方案對比優點:方案A:
  • 可以對任意介面進行undo操作;
  • 邏輯簡單,undo時無需操作資料庫;
方案B:
  • 操作真實反映到了資料庫;
  • 無需限制undo到期時間;
缺點方案A:
  • 訪問可undo介面後,再訪問非undo介面,之前邏輯不能undo;
方案B:
  • 邏輯較為複雜,undo需要做資料庫操作;
  • 並非所有操作都能夠undo;
方案實現

通過上邊的方案對比,我發現Plan A更簡單、靈活,因此決定實現Plan A。

使用過Koa的通許都知道,koa的中介軟體非常強大(類似Java web開發中的攔截器),它能夠攔截所有請求並執行一些邏輯,例如計算API請求到響應時間長度等,這裡我們就可以使用這個特性將需要Undo的API順延強制。

首先我們要設定Undo的逾時時間,以及那些API需要Undo:

var apis = (options || {}).apis;var expired = (options || {}).expired || 3000;

還要明確當前訪問API的使用者:

/** * `x-identify-key` is used to identify the user of this request, * one user can not undo another`s request. */var user = context.header['x-identify-key'];

然後順延強制API邏輯:

var undo = yield delayNext(user, expired, context);

如果使用者沒有調用Undo介面,則執行邏輯,否則返回’undo’:

if (!undo) { return yield next; }this.body = 'undo';

如果使用者調用Undo介面,移除順延強制的邏輯;調用其他介面則立即執行延遲的邏輯:

clearTimeout(undoObj.timeoutId);if (path === '/undo' && method === 'POST') {  undoObj.delayFn.call(undoObj.context, true);  context.body = 'done';  return;} else if (undoObj.delayFn) {  undoObj.delayFn.call(undoObj.context, false);}

具體實現邏輯大概就這些,完整代碼如下:

/** * Store users' undo context *  * @type {Object} */var undos = {};/** * Expose `undo` * * @param {Object} options Config object for undo * @example * { *   expired: 3000 * } */module.exports = function (options) {  var apis = (options || {}).apis;  var expired = (options || {}).expired || 3000;  return function* (next) {    var context = this;    var path = context.path;    var needUndo = false;    if (apis && Array.isArray(apis) && apis.length) {      needUndo = apis.filter(function (api) {        return path === api;      }).length;    }    if (!needUndo && path !== '/undo') { return yield next; }    var method = context.method;    /**     * Can not undo get request.     */    if (method === 'GET') { return yield next; }    /**     * 'x-identify-key' is used to identify the user of this request,     * one user can not undo another's request.     */    var user = context.header['x-identify-key'];    if (!user) { return yield next; }    var undoObj = undos[user];    if (undoObj) {      clearTimeout(undoObj.timeoutId);      if (path === '/undo' && method === 'POST') {        undoObj.delayFn.call(undoObj.context, true);        context.body = 'done';        return;      } else if (undoObj.delayFn) {        undoObj.delayFn.call(undoObj.context, false);      }    }    var undo = yield delayNext(user, expired, context);    if (!undo) { return yield next; }    this.body = 'undo';  };};/** * Block the logic for specified ms. * * @param {String} user The user's identity * @param {String} expired The expired ms * @param {Object} context The koa context object * @api private */function delayNext(user, expired, context) {  return function (callback) {    var delayFn = function (undo) {      delete undos[user];      callback(null, undo);    };    var timeoutId = setTimeout(delayFn, expired);    undos[user] = {      timeoutId: timeoutId,      delayFn: delayFn,      context: context    };  };}
項目相關

目前此項目託管在Github上,https://github.com/sweetvvck/koa-undo,koa-undo具體使用方法項目首頁有詳細介紹,感興趣的同學歡迎提Issue、PR;同時koa-undo也發布到了Npm上,https://www.npmjs.com/package/koa-undo ,歡迎大家使用。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.