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

資訊專欄INFORMATION COLUMN

indexedDB事務功能的Promise化封裝

zombieda / 2053人閱讀

摘要:綜上,對進行一定的封裝,來簡化編碼操作。化的嘗試對于這種帶大量回調的,使用進行異步化封裝是個好主意。因此包括在內的所有異步方法都會強制中止當前事務。這就決定了一個事務內部的所有操作必須是同步完成的。目前只實現(xiàn)了和,其他的有待下一步工作。

前言

本文是介紹我在編寫indexedDB封裝庫中誕生的一個副產品——如何讓indexedDB在支持鏈式調用的同時,保持對事務的支持。
項目地址:https://github.com/woodensail/indexedDB

2015/11/12 注:這篇文章的思路有問題,大家看看了解一下就行,不要這么干。更好的做法已經寫在了下一篇中。大家可以去看一下,順便幫忙點個推薦或者收藏一個。
地址:http://segmentfault.com/a/1190000003984871

indexedDB的基本用法
var tx = db.transaction("info", "readonly");
var store = tx.objectStore("info");
store.get("id").onsuccess = function (e) {
    console.log(e.target.result);
};

上面這段代碼中,開啟了一個事務,并從名為info的store中取得了key為id的記錄,并打印在控制臺。
其中打印的部分寫在了onsuccess回調中,如果我們希望把取出的id加1然后返回就需要這樣:

// 方案1
var tx = db.transaction("info", "readwrite");
var store = tx.objectStore("info");
store.get("id").onsuccess = function (e) {
    store.put({key:"id",value:e.target.result.value + 1}).onsuccess = function (e) {
        ……
    };
};

// 方案2
var tx = db.transaction("info", "readwrite");
var store = tx.objectStore("info");
var step2 = function(e){
    store.put({key:"id",value:e.target.result.value + 1}).onsuccess = function (e) {
        ……
    };
}
store.get("id").onsuccess = step2;

前者用到了嵌套回調,后者則需要將業(yè)務流程拆散。
綜上,對indexedDB進行一定的封裝,來簡化編碼操作。

Promise化的嘗試

對于這種帶大量回調的API,使用Promise進行異步化封裝是個好主意。
我們可以做如下封裝:

function put(db, table, data ,tx) {
    return new Promise(function (resolve) {
        var store = tx.objectStore(table);
        store.put(data).onsuccess = function (e) {
            resolve(e);
        };
    });
}

var tx = db.transaction("info", "readwrite");
Promise.resolve().then(function(){
    put(db, "info", {……}, tx)
}).then(function(){
    put(db, "info", {……}, tx)
});

看上去這么做是沒有問題的,但是實質上,在存儲第二條數(shù)據(jù)時,會報錯并提示事務已被停止。

事務與Promise的沖突

When control is returned to the event loop, the implementation MUST set the active flag to false.

——摘自W3C推薦標準(W3C Recommendation 08 January 2015)

如同上面的引用所說,目前的W3C標準要求在控制權回到事件循環(huán)時,當前開啟的事務必須被設置為關閉。因此包括Promise.then在內的所有異步方法都會強制中止當前事務。這就決定了一個事務內部的所有操作必須是同步完成的。
也真是基于這個原因,我沒有在github上找到實現(xiàn)鏈式調用的indexedDB封裝庫。
其中寸志前輩的BarnJS中到是有鏈式調用,然而只是實現(xiàn)了Event.get().then()。也就是只能一次數(shù)據(jù)庫操作,一次結果處理,然后就結束。并不能串聯(lián)多個數(shù)據(jù)庫操作在同一個事務內。

不夠要實現(xiàn)鏈式調用其實也不難,關鍵的問題就在于Promise本身是為異步操作而生的,因此會在鏈式調用的各個函數(shù)中返回事件循環(huán),從而減少網頁的卡頓。所以我們就需要實現(xiàn)一個在執(zhí)行每個函數(shù)過程之間不會返回事件循環(huán)的Promise,也就是一個同步化的Promise。

也許是這個要求太過奇葩,我沒發(fā)現(xiàn)網上有提供同步化執(zhí)行的promise庫。所以只能自己實現(xiàn)一個簡單的。雖然功能不全,但也能湊活用了。下面是使用樣例和詳細代碼解釋,完整代碼見github。

使用樣例
// 這句是我封裝過后的用法,等效于:
// var tx = new Transaction(db, "info", "readwrite");
var tx = dbObj.transaction("info", "readwrite");

//正常寫法
tx.then(function () {
    tx.get("info", "a");
    tx.get("info", "b");
}).then(function (a, b) {
    tx.put("info", {key : "c", value : Math.max(a.v, b.v));
})

//偷懶寫法
tx.then(function () {
    tx.getKV("info", "a");
    tx.getKV("info", "b");
}).then(function (a, b) {
    tx.putKV("info", "c",  Math.max(a, b));
})
代碼解釋
var Transaction = function (db, table, type) {
    this.transaction = db.transaction(table, type);
    this.requests = [];
    this.nexts = [];
    this.errorFuns = [];
};
Transaction.prototype.then = function (fun) {
    var _this = this;
    // 若errored為真則視為已經出錯,直接返回。此時后面的then語句都被放棄。
    if (this.errored) {
        return this;
    }
    // 如果當前隊列為空則將自身入隊后,立刻執(zhí)行,否則只入隊,不執(zhí)行。
    if (!_this.nexts.length) {
        _this.nexts.push(fun);
        fun(_this.results);
        _this.goNext();
    } else {
        _this.nexts.push(fun);
    }
    // 返回this以實現(xiàn)鏈式調用
    return _this;
};

Transaction的初始化語句和供使用者調用的then語句。

Transaction.prototype.put = function (table, data) {
    var store = this.transaction.objectStore(table);
    this.requests.push([store.put(data)]);
};
Transaction.prototype.get = function (table, key) {
    var store = this.transaction.objectStore(table);
    this.requests.push([store.get(key)]);
};
Transaction.prototype.putKV = function (table, k, v) {
    var store = this.transaction.objectStore(table);
    this.requests.push([store.put({k, v})]);
};
Transaction.prototype.getKV = function (table, key) {
    var store = this.transaction.objectStore(table);
    this.requests.push([store.get(key), item=>(item || {}).v]);
};

所有的函數(shù)都在發(fā)起數(shù)據(jù)庫操作后將返回的request對象暫存入this.requests中。
目前只實現(xiàn)了put和get,其他的有待下一步工作。另外,getKV和setKV是專門用于存取key-value數(shù)據(jù)的,要求被存取的store包含k,v兩個字段,其中k為主鍵。

// 該語句會在鏈式調用中的每個函數(shù)被執(zhí)行后立刻調用,用于處理結果,并調用隊列中的下一個函數(shù)。
Transaction.prototype.goNext = function () {
    var _this = this;
    // 統(tǒng)計前一個函數(shù)塊中執(zhí)行的數(shù)據(jù)庫操作數(shù)量
    var total = _this.requests.length;
    // 清空已完成數(shù)據(jù)庫操作計數(shù)器
    _this.counter = 0;
    // 定義全部操作執(zhí)行完畢或出差后的回調函數(shù)
    var success = function () {
        // 當已經有錯誤出現(xiàn)時,放棄下一步執(zhí)行
        if (_this.errored) {
            return;
        }
        // 將隊首的節(jié)點刪除,也就是剛剛執(zhí)行完畢的節(jié)點
        _this.nexts.shift();
        _this.requests = [];
        // 從返回的event集合中提取出所有result,如果有parser則使用parser。
        _this.results = _this.events.map(function (e, index) {
            if (_this.parser[index]) {
                return _this.parser[index](e.target.result);
            } else {
                return e.target.result;
            }
        });
        
        //判斷隊列是否已經執(zhí)行完畢,否則繼續(xù)執(zhí)行下一個節(jié)點
        if (_this.nexts.length) {
            // 將節(jié)點的執(zhí)行結果作為參數(shù)傳給下一個節(jié)點,使用了spread操作符。
            _this.nexts[0](..._this.results);
            _this.goNext();
        }
    };
    // 初始化events數(shù)組,清空parser存儲器
    _this.events = new Array(total);
    _this.parser = {};

    // 若該請求內不包含數(shù)據(jù)庫操作,則視為已完成,直接調用success
    if (total === 0) {
        success();
    }

    // 對于每個請求將請求附帶的parser放入存儲區(qū)。然后綁定onsuccess和onerror。
    // 其中onsuccess會在每個請求成功后將計數(shù)器加一,當計數(shù)器等于total時執(zhí)行回調
    _this.requests.forEach(function (request, index) {
        _this.parser[index] = request[1];
        request[0].onsuccess = _this.onsuccess(total, index, success);
        request[0].onerror = _this.onerror;
    })
};
Transaction.prototype.onsuccess = function (total, index, callback) {
    var _this = this;
    return function (e) {
        // 將返回的event存入event集合中的對應位置
        _this.events[index] = e;
        _this.counter++;
        if (_this.counter === total) {
            callback();
        }
    }
};
Transaction.prototype.onerror = function (e) {
    // 設置錯誤標準
    this.errored = true;
    // 保存報錯的event
    this.errorEvent = e;
    // 一次調用所有已緩存的catch函數(shù)
    this.errorFuns.forEach(fun=>fun(e));
};
Transaction.prototype.cache = function (fun) {
    // 如果已設置錯誤標準則用緩存的event為參數(shù)立刻調用fun,否則將其存入隊列中
    if (this.errored) {
        fun(this.errorEvent);
    } else {
        this.errorFuns.push(fun);
    }
};

核心的goNext語句以及success與error的回調。catch類似then用于捕捉異常。

總結

好累啊,就這樣吧,以后再加其他功能吧。另外這里面用了不少es6的寫法。所以請務必使用最新版的edge或chrome或firefox運行。或者你可以手動把es6的寫法都去掉。

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

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/86187.html

相關文章

  • indexedDB事務功能Promise封裝(二)——利用generator完成同步改造

    摘要:在不可以用的前提下,無論是同步化或者鏈式操作都用不了。于是昨天我自己實現(xiàn)了一個簡單的同步執(zhí)行的,并以此為基礎實現(xiàn)了鏈式操作。 前言 本來這個系列應該不會這么快更新,然而昨晚寫完前一篇后才發(fā)現(xiàn)我的思路中有一個巨大的漏洞。導致我在前一篇中花費大量時間實現(xiàn)了一個復雜的Transaction類——其實完全有更簡單的方式來完成這一切。前篇:http://segmentfault.com/a/11...

    JackJiang 評論0 收藏0
  • html5 indexeddb簡明api

    摘要:網上搜來一堆,,幾乎沒有找到滿意的答案,經過匯總并結合自己的理解,封裝了一套簡單的是一個異步對象,必須使用回調函數(shù)方式進行調用打開一個數(shù)據(jù)庫,支持兩個參數(shù),第二個參數(shù)指定版本號,我沒用到,讓瀏覽器自己創(chuàng)建版本號。 網上搜來一堆api,demo,幾乎沒有找到滿意的答案,經過匯總并結合自己的理解,封裝了一套簡單的api // indexedDB是一個異步對象,必須使用回調函數(shù)方式進行調用 ...

    luckyw 評論0 收藏0
  • IndexedDB 簡單封裝

    摘要:之前我在開發(fā)過程中使用的是,可以直接寫查詢數(shù)據(jù)。,用鍵值模式存儲數(shù)據(jù),而且就是專門為小數(shù)量數(shù)據(jù)設計的。只能是字符串而且空間有限。下面是自己看了阮一峰的文章簡單的學習了下對這個瀏覽器數(shù)據(jù)庫有個大概的了解,下面是個人對簡單的封裝。IndexedDB?瀏覽器數(shù)據(jù)庫,是一個非關系型數(shù)據(jù)庫,數(shù)據(jù)形式使用的是json,IndexedDB適合存儲大量數(shù)據(jù),它的API是異步調用的,當然他的api?也相對復雜...

    Songlcy 評論0 收藏0
  • 【譯】漸進式 Web App 離線存儲

    摘要:離線存儲數(shù)據(jù)的建議對尋址資源,使用這是的一部分。在到達儲量限制之前,兩種存儲機制都會一直進行存儲。則沒有對存儲量做出限制,只是在之后會彈出提醒。是異步的基于回調函數(shù),但它同樣不支持。也是異步的基于回調函數(shù),在和中可以工作雖然使用的是同步。 拖拖拉拉好久,終于把個人博客整出來了。鳴謝 @pinggod。 厚著臉安利一下,地址是 http://www.wemlion.com/。歡迎訪問,歡...

    Joyven 評論0 收藏0
  • 【譯】漸進式 Web App 離線存儲

    摘要:離線存儲數(shù)據(jù)的建議對尋址資源,使用這是的一部分。在到達儲量限制之前,兩種存儲機制都會一直進行存儲。則沒有對存儲量做出限制,只是在之后會彈出提醒。是異步的基于回調函數(shù),但它同樣不支持。也是異步的基于回調函數(shù),在和中可以工作雖然使用的是同步。 拖拖拉拉好久,終于把個人博客整出來了。鳴謝 @pinggod。 厚著臉安利一下,地址是 http://www.wemlion.com/。歡迎訪問,歡...

    Charlie_Jade 評論0 收藏0

發(fā)表評論

0條評論

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