亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

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

JackJiang / 2758人閱讀

摘要:在不可以用的前提下,無論是同步化或者鏈?zhǔn)讲僮鞫加貌涣?。于是昨天我自己實現(xiàn)了一個簡單的同步執(zhí)行的,并以此為基礎(chǔ)實現(xiàn)了鏈?zhǔn)讲僮鳌?/p>

前言

本來這個系列應(yīng)該不會這么快更新,然而昨晚寫完前一篇后才發(fā)現(xiàn)我的思路中有一個巨大的漏洞。導(dǎo)致我在前一篇中花費大量時間實現(xiàn)了一個復(fù)雜的Transaction類——其實完全有更簡單的方式來完成這一切。
前篇:http://segmentfault.com/a/1190000003982058
項目地址:https://github.com/woodensail/indexedDB

昨天的疏忽

昨天在設(shè)計封裝庫時,一開始是打算利用《co模塊的前端實現(xiàn)》中實現(xiàn)的async庫來完成數(shù)據(jù)庫訪問的同步化。然而嘗試之后就發(fā)現(xiàn)并不可行,問題在前篇中提到過,出在Promise的機制上。于是得出結(jié)論:indexedDB不可以用原生Promise進(jìn)行封裝。
在不可以用Promise的前提下,無論是同步化或者鏈?zhǔn)讲僮鞫加貌涣?。于是昨天我自己實現(xiàn)了一個簡單的同步執(zhí)行的Promise,并以此為基礎(chǔ)實現(xiàn)了鏈?zhǔn)讲僮鳌?br>我在昨天的文章寫完之后才突然想到,既然沒有Promise就沒法實現(xiàn)同步化鏈?zhǔn)讲僮?/strong>,那么我自己實現(xiàn)完P(guān)romise后完全可以不用使用鏈?zhǔn)讲僮?,直接一步到位實現(xiàn)同步化。所以這篇文章就是關(guān)于如何完成indexedDB同步化封裝。

使用樣例

這是一段最基礎(chǔ)的用法,依然和昨天一樣實現(xiàn)了get,put,getKV,putKV,四個函數(shù)。
這種寫法下每個操作是多帶帶事務(wù)的,無法保證原子性。

async(function* () {
    var db = yield new DB("test");
    yield db.put("info", {k: "async", v: 1});
    var result1 = yield db.get("info", "async");
    console.log(result1.v);
    
    yield db.putKv("info", "async", "1");
    var result2 = yield db.getKv("info", "async");
    console.log(result2);
}).catch(function (e) {
    console.log(e);
});

首先打開一個事務(wù)然后作為參數(shù)傳遞給數(shù)據(jù)庫訪問函數(shù)即可啟用事務(wù)支持。
下面這兩個操作是在同一個事務(wù)中的。

async(function* () {
    var db = yield new DB("test");
    var tx = db.transaction("info", "readwrite");
    yield db.put("info", {k: "async", v: 1}, tx);
    var result1 = yield db.get("info", "async", tx);
    console.log(result1.v);
}).catch(function (e) {
    console.log(e);
});

在開啟事務(wù)時,第三個參數(shù)填true,可以將當(dāng)前事務(wù)作為默認(rèn)事務(wù)。后面的操作將自動使用該事務(wù)。需要在使用完畢后調(diào)用transactionEnd手動清除默認(rèn)事務(wù)。

async(function* () {
    var db = yield new DB("test");
    db.transaction("info", "readwrite", true);
    yield db.put("info", {k: "async", v: 1});
    var result1 = yield db.get("info", "async");
    console.log(result1.v);
    db.transactionEnd();
}).catch(function (e) {
    console.log(e);
});
實現(xiàn)Promise

這是一個不完全版的Promise實現(xiàn),只提供了最基本的then和catch以及他們的鏈?zhǔn)秸{(diào)用。反正也夠async用了。
暫時沒有提供對Promise.all的支持,我估計要支持得修改async庫才行,所以就以后再說吧。

var DbPromise = function (fun) {
    this.state = "pending";
    this.resolveList = [];
    this.rejectList = [];
    var _this = this;
    fun(function () {
        _this.resolve.apply(_this, arguments)
    }, function () {
        _this.reject.apply(_this, arguments)
    });
};
DbPromise.prototype = {};
DbPromise.prototype.resolve = function (data) {
    this.state = "resolved";
    this.data = data;
    var _this = this;
    this.resolveList.forEach(function (fun) {
        _this.data = fun(_this.data)
    });
};
DbPromise.prototype.reject = function (data) {
    this.state = "rejected";
    this.error = data;
    this.rejectList.forEach(function (fun) {
        fun(data);
    });
};
DbPromise.prototype.then = function (fun) {
    if (this.state === "pending") {
        this.resolveList.push(fun);
    } else {
        this.data = fun(this.data);
    }
    return this;
};
DbPromise.prototype.catch = function (fun) {
    if (this.state === "pending") {
        this.rejectList.push(fun);
    } else {
        fun(this.error);
    }
    return this;
};
實現(xiàn)數(shù)據(jù)庫封裝類

定義class DB,打開數(shù)據(jù)庫的操作定義在_open中,會在后面介紹

var DB = function (name, upgrade, version) {
    var _this = this;
    // 可以在其他js文件中通過向DB.dbMap添加成員的方式來預(yù)定義數(shù)據(jù)庫
    // 如果是已經(jīng)預(yù)定義過的數(shù)據(jù)庫就可以調(diào)用new DB(name)來打開
    // 否則需要調(diào)用new DB(name, upgrade, version),填寫upgrade響應(yīng)函數(shù)和版本號
    if (DB.dbMap[name]) {
        var map = DB.dbMap[name];
        return _open(name, map.upgrade, map.version).then(function (db) {
            _this.db = db;
            return _this;
        }).then(map.nextStep);
    } else {
        return _open(name, upgrade, version).then(function (db) {
            _this.db = db;
            return _this;
        });
    }
};
DB.prototype = {};

打開事務(wù)和取消關(guān)閉事務(wù)的方法。

DB.prototype.transaction = function (table, type, asDefault) {
    // 根據(jù)給定的目標(biāo)和類型打開當(dāng)前數(shù)據(jù)庫的事務(wù)
    var tx = _transaction(this.db, table, type);
    // 如果asDefault為真,則緩存該事務(wù)將其作為默認(rèn)事務(wù)。
    // 注意目前同時設(shè)置多個默認(rèn)事務(wù)是會沖突的,
    // 這種情況理論上有極小的可能性在異步操作中出現(xiàn),我會在接下來的版本中改正這一點。
    if (asDefault) {
        this.tx = tx;
    }
    return tx;
};
//取消默認(rèn)事務(wù)
DB.prototype.transactionEnd = function () {
    this.tx = void 0;
};
function _transaction(db, table, type) {
    return db.transaction(table, type);
}

具體的數(shù)據(jù)庫操作函數(shù)。其實是對_put等函數(shù)的封裝。

// tx || this.tx 指的是優(yōu)先使用參數(shù)指定的事務(wù),其次使用默認(rèn)事務(wù)
DB.prototype.put = function (table, data, tx) {
    return _put(this.db, table, data, tx || this.tx);
};
DB.prototype.get = function (table, name, tx) {
    return _get(this.db, table, name, tx || this.tx);
};
DB.prototype.clear = function (table, tx) {
    return _clear(this.db, table, tx || this.tx);
};

//這兩個是對get和put的特殊封裝,多了參數(shù)和結(jié)果的預(yù)處理,簡化了參數(shù)和返回值的格式
DB.prototype.getKv = function (table, k, tx) {
    return _get(this.db, table, k, tx).then(o=>(o || {}).v);
};
DB.prototype.putKv = function (table, k, v, tx) {
    return _put(this.db, table, {k, v}, tx);
};

_open,_put,_get,_clear的實現(xiàn)由于后三者類似,所以只貼了_put。需要后兩點代碼請查看github。

function _open(name, upgrade, version) {
    // 返回自定義Promise供async庫調(diào)用
    return new DbPromise(function (resolve, reject) {
        // 打開指定數(shù)據(jù)庫的指定版本
        var request = indexedDB.open(name, version);
        // 設(shè)置升級操作
        request.onupgradeneeded = upgrade;
        // 綁定success和error,其中成功后會返回打開的數(shù)據(jù)庫對象
        request.onsuccess = function (e) {
            resolve(request.result);
        };
        request.onerror = reject;
    });
}
function _put(db, table, data, tx) {
    // 返回自定義Promise供async庫調(diào)用
    return new DbPromise(function (resolve, reject) {
        // 如果沒有提供事務(wù)則創(chuàng)建新事務(wù)
        tx = tx || db.transaction(table, "readwrite");
        // 打開store并進(jìn)行操作
        var store = tx.objectStore(table);
        var request = store.put(data);
        // 設(shè)置回調(diào)
        request.onsuccess = function () {
            resolve(request.result);
        };
        request.onerror = reject;

    });
}
總結(jié)

基本上,在實現(xiàn)了DbPromise之后其他部分的實現(xiàn)方式就是按老一套來就行了,非常的簡單。我昨天只是光棍節(jié)腦袋抽筋沒反應(yīng)過來而已。
現(xiàn)在的庫已經(jīng)可以當(dāng)做基本的Key-Value數(shù)據(jù)庫來用了,以后我會進(jìn)一步添加更多的方法。各位親們,推薦或者收藏一下唄

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

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/86179.html

Failed to recv the data from server completely (SIZE:0/8, REASON:closed)