
前面已經有提到indexedDB是一個在browser運行的Database,這裡我列出幾項主要的特性:
不過在我的project中,為了避免使用callback function,我使用了第三方的套件(由jakearchibald提供),這讓我能使用promise來去操作indexedDB。(記得將code複製到project中js目錄下,並加入到pre-cache中)
IndexedDB Browser Support (96%的瀏覽器都支援,其實算相當不錯的)
接下來我就要將用戶的貼文資料(dynamic data)從原本暫存在cache,移植到indexedDB中囉!!
首先要在sw.js中,導入indexedDB的第三方套件。同時為了之後寫的程式碼能重複利用,我將針對indexedDB的操作寫在utility.js中,所以也需要導入:
importScripts('/src/js/idb.js');
importScripts('/src/js/utility.js');
來看一下在utility.js中要怎麼建立indexedDB的object store並將資料寫入:
var dbPromise = idb.open('post-store', 1, function(db) {
    if(!db.objectStoreNames.contains('posts')) {
        db.createObjectStore('posts', {keyPath: 'id'});
    }
});
function writeData(objectStore, data) {
    return dbPromise.then(function(db) {
        var tx = db.transaction(objectStore, 'readwrite');  // first step
        var store = tx.objectStore(objectStore);   // second step
        store.put(data);   // third step
        return tx.complete;
    });
}
透過第三方套件,我可以使用idb.open()來建立一個資料庫,需要輸入3個參數(1. 資料庫名稱、2. 資料庫版本[可以隨喜好設定,但不能相同]、3. callback function)。而這個callback function會以建立好的indexedDB object作為輸入,來去操作這個資料庫。
所以在callback function中,我在post-store資料庫中新增一個「名為posts的object store」,而且第二個參數是要去設定在這個object store中,我們要以哪個欄位做為key值。
接著寫要怎麼將firebase的貼文資訊寫入indexedDB呢?事實上操作indexedDB有一個標準執行流程:
可以看到這三個步驟就是上面writeData() function中的3 step
最後在sw.js中,將從firebase裡fetch回來的資料改成儲存到indexedDB:
// Cache then Network
self.addEventListener('fetch', function(event) {
    var url = 'https://trip-diary-f56de.firebaseio.com/posts.json';
    
    // 要修改的地方
    if(event.request.url.indexOf(url) > -1) {
        event.respondWith(
            fetch(event.request).then(function(res) {
                var clonedRes = res.clone();
                clonedRes.json().then(function(data) {
                    for(var key in data) {
                        writeData('posts', data[key]);
                    }
                });
                return res;
            })
        );
    } else if(isInArray(event.request.url, STATIC_FILES)) {
        event.respondWith(
            caches.match(event.request)
        );
    } else {
        event.respondWith(
            caches.match(event.request).then(function(response) {
                if(response) {
                    return response;
                } else {
                    return fetch(event.request).then(function(res) {
                        return caches.open(CACHE_DYNAMIC_NAME).then(function(cache) {
                            // trimCache(CACHE_DYNAMIC_NAME, 20);
                            cache.put(event.request.url, res.clone());
                            return res;
                        })
                    }).catch(function(err) {
                        return caches.open(CACHE_STATIC_NAME).then(function(cache) {
                            if(event.request.headers.get('accept').includes('text/html')) {
                                return cache.match('/offline.html');
                            }
                        });
                    });
                }
            })
        );
    }
});
說明一下,這裡我把firebase fetch回來的response,複製(clone)完後將資料轉成javascript object型式。接著用一個for loop把posts裡面的每一則貼文寫入到"posts" object store中。
來看一下畫面執行的結果吧:![]()

發現我們已經成功地將firebase回傳dynamic data儲存至indexedDB中了,它的key就是我們當初設定的id欄位,value就是貼文的json object。
Day15 結束!! ![]()