在前面的一篇文章中,我們已經實現了使用indexedDB實現ajax本地資料儲存的功能,詳情,請看這篇文章。現在我們需要把上面的一篇文章中的程式碼使用promise結構來重構下。我們為什麼需要使用promise來重構呢?我們之前一直使用 indexedDB中的程式碼,但是在indexedDB中,我們程式碼很大程度上依賴於回撥,如果我們的程式碼越來越多,我們需要的回撥巢狀就越來越多,這對於後期程式碼維護不是很好。
比如我們可以看看我們之前的程式碼如下所示:
// 開啟或建立 store-data 資料庫 var result = window.indexedDB.open('store-data', 3); // 監聽error函式觸發 result.onerror = function(event) { console.log("DataBase error:", event.target.error); } // 監聽當前版本號被升級的時候觸發該函式 result.onupgradeneeded = function(event) { var db = event.target.result; /* 是否包含該物件倉庫名(或叫表名)。如果不包含就建立一個。 該物件中的 keyPath屬性id為主鍵 */ if (!db.objectStoreNames.contains('store')) { db.createObjectStore("store", { keyPath: "id", autoIncrement: true }); } } result.onsuccess = function(event) { var targetValue = event.target.result; /* 1. 使用 targetValue.transaction(storeName, transactionMode) 來建立事務 2. 建立事務之後,我們使用 targetValue.transaction(storeName, transactionMode).objectStore(storeName) 這個方法,拿到 IDBObjectStore物件。 */ var objectStore = targetValue.transaction(storeName, transactionMode).objectStore(storeName); var request = objectStore.add({id: 3, name: 'kongzhi12', age: 31}); request.onsuccess = function(event) { console.log('回撥函式成功'); } request.onerror = function(event) { console.log("DataBase error:", event.target.error); } }
如上程式碼,我們開啟了或建立了一個 store-data 資料庫,然後把onsuccess回撥附加到該請求上,在該onsuccess請求上,我們又有請求事件,接著有 onsuccess 回撥函式,依次類推,如果以後程式碼越來越複雜的時候,我們以後程式碼就一直變成回撥巢狀中,因此我們現在想使用promise方法來重構上面的程式碼,我們想要讓上面的程式碼變成如下所示這樣的:
openDatabase('store-data', 3).then(function(db) { return openObjectStore(db, "store", "readwrite"); }).then(function(objectStore){ return addObject(objectStore, {"id": 3, "name": 'kongzhi123', 'age': 31}); }).then(function(){ console.log('回撥成功'); }).catch(function(error) { console.log('DataBase error', error); });
我們希望變成如上的promise程式碼,我們希望將javascript非同步回撥的程式碼變成我們的promise程式碼。在重構我們的程式碼之前,我們先來看看我們的 XMLHttpRequest 程式碼,我們希望使用promise來重構該程式碼,在重構之前,我們先來看看XMLHttpRequest程式碼如下:
var xhr = new XMLHttpRequest(); xhr.onload = function() { // 處理響應 }; xhr.onerror = function() { // 處理錯誤 }; xhr.open("get", '/xxx.json', true); xhr.send();
如上這樣的程式碼,是我們之前的xmlHttpRequest程式碼,現在我們可以使用我們的promise來重構我們上面的程式碼,因此重構後的程式碼變成如下所示:
var promise_XHR = function(url, method) { return new Promise(function(resolve, reject) { var xhr = new XMLHttpRequest(); xhr.onload = resolve; xhr.onerror = reject; xhr.open(method, url, true); xhr.send(); }); };
如上 promise_XHR 函式,該函式接收一個url 和 method引數,並返回了一個promise物件,該promise傳入了一個函式,該函式有兩個引數,代表成功和失敗的回撥,然後內部程式碼,我們建立了一個XMLHttpRequest物件,然後該物件 onload 函式的時候 把resolve 成功回撥賦值給他,然後 xhr.onerror 函式的時候,把 reject 拒絕函式傳遞給他,我們呼叫方式如下所示:
promise_XHR('/xxx.json', 'get').then(function(){ // 處理成功的回撥函式 }).catch(error) { // 處理我們異常的回撥函式 }
現在我們想把該方式使用到我們的 store.js 程式碼內部來。重構後的程式碼就變成了如下:
import axios from 'axios'; var DB_VERSION = 1; var DB_NAME = 'store-data2'; var openDataBase = function() { return new Promise(function(resolve, reject) { if (!window.indexedDB) { reject("indexedDB not supported"); } // 開啟或建立 store-data 資料庫 var result = window.indexedDB.open(DB_NAME, DB_VERSION); // 監聽error函式觸發 result.onerror = function(event) { console.log("DataBase error:", event.target.error); } // 監聽當前版本號被升級的時候觸發該函式 result.onupgradeneeded = function(event) { var db = event.target.result; /* 是否包含該物件倉庫名(或叫表名)。如果不包含就建立一個。 該物件中的 keyPath屬性id為主鍵 */ if (!db.objectStoreNames.contains('store')) { db.createObjectStore("store", { keyPath: "id", autoIncrement: true }); } } result.onsuccess = function(event) { resolve(event.target.result); } }); }; /* @param {storeName} 倉庫名或表名 @param {transactionMode} 事務模式 readOnly 只讀,readwrite 可讀可寫 */ var openObjectStore = function(db, storeName, transactionMode) { return db.transaction(storeName, transactionMode).objectStore(storeName); }; var getStore = function (successCallback) { return new Promise(function(resolve, reject) { openDataBase().then(function(db) { var objectStore = openObjectStore(db, 'store'); var datas = []; objectStore.openCursor().onsuccess = function(event) { var cursor = event.target.result; if (cursor) { datas.push(cursor.value); cursor.continue(); } else { if (datas.length > 0) { resolve(datas); } else { getDataFromServer().then(function(d) { openDataBase().then(function(db) { var objectStore = openObjectStore(db, "store", "readwrite"); for (let i = 0; i < datas.length; i++) { objectStore.add(datas[i]); } resolve(datas); }); }); } } } }).catch(function() { getDataFromServer().then(function(datas) { resolve(datas); }); }); }); }; function getDataFromServer() { return new Promise(function(resolve, reject) { axios.get("http://localhost:8081/public/json/index.json", resolve); }); } var addToObjectStore = function(storeName, object) { return new Promise(function(resolve, reject) { openDataBase().then(function(db) { openObjectStore(db, storeName, 'readwrite').add(object).onsuccess = resolve; }).catch(function(error) { reject(error); }) }); }; var updateInObjectStore = function(storeName, id, object) { return new Promise(function(resolve, reject) { openDataBase().then(function(db) { openObjectStore(db, storeName, "readwrite").openCursor().onsuccess = function(event) { var cursor = event.target.result; if (!cursor) { reject("store-data not found"); } if (cursor.value.id === id) { cursor.put(object).onsuccess = resolve; return; } cursor.continue(); } }).catch(function(){ reject(error); }) }); } window.openDataBase = openDataBase; window.openObjectStore = openObjectStore; window.addToObjectStore = addToObjectStore; window.updateInObjectStore = updateInObjectStore; window.getStore = getStore;
然後我們需要在我們的 myAccount.js 程式碼改成如下初始化所示:
import $ from 'jquery'; $(function() { openDataBase("store-data2", 2).then(function(db) { return openObjectStore(db, "store", "readwrite"); }).then(function(objectStore) { return addToObjectStore("store", {id: 1, name: 'kongzhi111', age: 11}); }).then(function() { console.log('新增成功'); }).catch(function(error) { console.log("資料庫載入失敗", error); }); /* var addStore = function(id, name, age) { var obj = { id: id, name: name, age: age }; addToObjectStore("store", obj); renderHTMLFunc(obj); $.getJSON("http://localhost:8081/public/json/index.json", obj, function(data) { updateDisplay(data); }); }; $("#submit").click(function(e) { addStore(3, 'longen1', '111'); }); $("#update").click(function(e) { $.getJSON("http://localhost:8081/public/json/index.json", {id: 1}, function(data) { updateInObjectStore("store", 1, data); updateDisplay(data); }); }); */ });
然後會向我們的資料庫中插入一條資料,我們重新整理頁面後檢視我們的本地資料庫如下所示: