虎瀾集: 網頁與資料庫 (5)
October 15th, 2016
說到 IndexedDB 這個規格的奇葩點,那就有的講了,反正敝社做 IndexedDB 的全部都知道我這號愛抱怨的人物,所以就用中文再開一次地圖炮吧哈哈哈 … IndexedDB 在 Mozilla 有一份非常完整的詳細教程,我們直接抓其中的一部份出來看,就看用最多的 data retrieval 好了
db.transaction("customers").objectStore("customers").get("444-44-4444").onsuccess = function(event) {
alert("Name for SSN 444-44-4444 is " + event.target.result.name);
};
看起來很正常啊,有什麼問題嗎? 沒什麼問題,就是它天生會跑的慢一點。首先,這一小段程式其實會 fire 兩個 event: get success 和 transaction complete。所以若你用這種方法撈 1000 行資料,就會有 1001 個 event (1000 個 get success 加一個 transaction complete)。當年我用 HP Z620 量的時候每個 event 差不多 16μs,所以撈 1000 行的基本稅率就是在你的 JS main thread 上浪費 16ms。那如果用 cursor 呢? 對不起,一樣。要記得這是在 HP Z620 有兩顆 Xeon 的工作站跑的數字,真的到用戶的電腦上,那稅就不只這麼一點了。另外我是很客氣的用 1000 行這種微不足道的數字來算的,如果是做照片管理或記帳的苦主,1000 筆這種數字塞牙縫都不夠。這還只算 eventing 的時間,indexing/data transfer 那個我們通通都沒算的。
接下來就是見證奇蹟式的奇葩的時刻。大部份 JS developer 是不可能用 raw API 去硬幹的,所以一般會用包的好好的 promise 式的 API,例如 indexed-db.es6 。比方說,寫幾行資料進資料庫:
db.runTransaction(['foo', 'bar'], (foo, bar, abort) => {
return Promise.all([foo.add('some row'), bar.add('some row')]);
}).then(() => {
console.log('rows inserted');
});
很簡單嘛,沒什麼問題。好,若是你把你的程式這樣改的話,那你就完蛋了:
db.runTransaction(['foo', 'bar'], (foo, bar, abort) => {
pingServer(); // Fire a heartbeat XHR to server, result don't care
return Promise.all([foo.add('some row'), bar.add('some row')]);
}).then(() => {
console.log('rows inserted');
});
你很快會發現你的程式永遠都無法寫入資料,因為 transaction auto-commit … 這一關不知卡死多少人,因為很多時候我們要和 server 同步的方式就是如以下的 pseudo code:
BEGIN TRANSACTION
communicate to server end point 1
process data
write to database
communicate to server end point 2
process data
write to database
END TRANSACTION
目前 IndexedDB 的設計會讓上述的 pseudo code 極難完成,你要嘛就是改設計,要嘛就是用我寫的 Lovefield,不然就是自己做 caching 和 transaction management 最後再一次寫進去資料庫,沒有太多的選擇。
我好像忘記講一件很厲害的事,如果你的程式常常要做類似下面的事情
SELECT a.foo, b.bar
FROM a, b
WHERE a.id = b.id AND
a.timestamp < $1 AND
b.volume < $2
ORDER BY a.timestamp DESC
LIMIT $3
SKIP $4
恭喜你,請想想看你是否要重新設計一下你的資料結構。你看到的所有 WHERE, ORDER BY, LIMIT, SKIP 全部都要你自己用 JavaScript 做出來,IndexedDB 幫不了你。看到這裡是不是覺得直接回頭用 PHP+MySQL 或 ASP.Net 沒有那麼愚蠢了? 這就是 NoSQL hype 可怕的地方。它把所有需要 relational functionality 的人都逼回去用 server side solution,再大剌剌的說 client side 沒有 relational 的需求,要 NoSQL 才夠 webby 才夠潮夠威,然後就繼續好棒棒下去了。
所以你要是問我 IndexedDB 到底有什麼用呢? 我只能告訴你如果你的 server 端是 document-based 的資料庫,然後你也不太 care 多重條件查詢的話,IndexedDB 還蠻好用。除此之外的所有狀況,你大概還是保持你現有的 server-side solution 多買點 AWS 或 GCE,要不然就學 G-Mail 來用我寫的 Lovefield 吧。
謎之聲: 看,這篇很像廣告文耶。
我: 看,我自己的 blog 要怎麼廣告就怎麼廣告,不行逆?
謎之聲: 看,G-Mail 用你的東西,吹,我讓你吹 ...
我: inbox.google.com 加入後,refresh 一次,自己去 JavaScript console 看看打 lf 會出來什麼東西吧 ...