Mostly failed experiment: tag_autocomplete indexeddb.

The current system has bad performance when you've got 100,000+ tags.
I discovered that when the server returns 304, the browser gives the
ajax a 200 with the full response, and it's not clear to me if js can
know it got a 304. So, the tag set is being fully re-parsed from the
response on every page load. I was thinking that I should store that in
IndexedDB to avoid the parsing step, but... since the JSON.parse is
done by my common.get before it hits this function, it's meaningless.
Not to mention I still have to rebuild the datalist on every page since
of course that state isn't shared between tabs. Not worth the DB stuff.
We'll see what happens next.
This commit is contained in:
voussoir 2020-09-29 16:51:59 -07:00
parent 3a8aadf6aa
commit 7e58c95f15
6 changed files with 135 additions and 37 deletions

View file

@ -1,4 +1,5 @@
import flask; from flask import request
import time
import etiquette
@ -68,7 +69,7 @@ def post_tag_remove_child(tagname):
def get_all_tag_names():
all_tags = list(common.P.get_all_tag_names())
all_synonyms = common.P.get_all_synonyms()
response = {'tags': all_tags, 'synonyms': all_synonyms}
response = {'updated': int(time.time()), 'tags': all_tags, 'synonyms': all_synonyms}
return jsonify.make_json_response(response)
@site.route('/tag/<specific_tag_name>')

View file

@ -347,6 +347,13 @@ function edit(tag_name, name, description, callback)
common.post(url, data, callback);
}
api.tags.get_all_tags =
function get_all_tags(callback)
{
const url = "/all_tags.json";
common.get(url, callback);
}
api.tags.remove_child =
function remove_child(tag_name, child_name, callback)
{

View file

@ -1,34 +1,64 @@
const tag_autocomplete = {};
tag_autocomplete.tagset = {"tags": [], "synonyms": {}};
tag_autocomplete.tags = new Set();
tag_autocomplete.synonyms = {};
tag_autocomplete.DATALIST_ID = "tag_autocomplete_datalist";
// {
// const db_name = "tag_autocomplete";
// const db_version = 1;
// const open_request = window.indexedDB.open(db_name, db_version);
// open_request.onsuccess = function(event)
// {
// const db = event.target.result;
// tag_autocomplete.db = db;
// console.log("Initialized db.");
// }
// open_request.onupgradeneeded = function(event)
// {
// const db = event.target.result;
// const tag_store = db.createObjectStore("tags", {"keyPath": "name"});
// const synonym_store = db.createObjectStore("synonyms", {"keyPath": "name"});
// const meta_store = db.createObjectStore("meta", {"keyPath": "key"});
// tag_store.createIndex("name", "name", {unique: true});
// synonym_store.createIndex("name", "name", {unique: true});
// console.log("Installed db schema.");
// }
// }
////////////////////////////////////////////////////////////////////////////////////////////////////
tag_autocomplete.init_datalist =
function init_datalist()
{
console.log("Init datalist.");
let datalist;
datalist = document.getElementById(tag_autocomplete.DATALIST_ID);
if (!datalist)
if (datalist)
{
datalist = document.createElement("datalist");
datalist.id = tag_autocomplete.DATALIST_ID;
document.body.appendChild(datalist);
return;
}
datalist = document.createElement("datalist");
datalist.id = tag_autocomplete.DATALIST_ID;
document.body.appendChild(datalist);
const fragment = document.createDocumentFragment();
common.delete_all_children(datalist);
for (const tag_name of tag_autocomplete.tagset["tags"])
for (const tag_name of tag_autocomplete.tags)
{
const option = document.createElement("option");
option.value = tag_name;
datalist.appendChild(option);
fragment.appendChild(option);
}
for (const synonym in tag_autocomplete.tagset["synonyms"])
for (const synonym in tag_autocomplete.synonyms)
{
const option = document.createElement("option");
option.value = tag_autocomplete.tagset["synonyms"][synonym] + "+" + synonym;
datalist.appendChild(option);
option.value = tag_autocomplete.synonyms[synonym] + "+" + synonym;
fragment.appendChild(option);
}
datalist.appendChild(fragment);
}
tag_autocomplete.normalize_tagname =
@ -79,49 +109,113 @@ tag_autocomplete.resolve =
function resolve(tagname)
{
tagname = tag_autocomplete.normalize_tagname(tagname);
if (tag_autocomplete.tagset["tags"].indexOf(tagname) != -1)
if (tag_autocomplete.tags.has(tagname))
{
return tagname;
}
if (tagname in tag_autocomplete.tagset["synonyms"])
if (tagname in tag_autocomplete.synonyms)
{
return tag_autocomplete.tagset["synonyms"][tagname];
return tag_autocomplete.synonyms[tagname];
}
return null;
}
tag_autocomplete.update_tagset_callback =
function update_tagset_callback(response)
// function update_stored_tags(data)
// {
// console.log("Updating db tags.");
// const updated = data.updated;
// const version_transaction = tag_autocomplete.db.transaction(["meta"], "readwrite");
// const meta_store = version_transaction.objectStore("meta");
// meta_store.add({"key": "updated", "val": updated});
// const tags_transaction = tag_autocomplete.db.transaction(["tags"], "readwrite");
// const tags_store = tags_transaction.objectStore("tags");
// for (const name of data.tags)
// {
// tags_store.add({"name": name});
// tag_autocomplete.tags.add(name);
// }
// const synonyms_transaction = tag_autocomplete.db.transaction(["synonyms"], "readwrite");
// const synonyms_store = synonyms_transaction.objectStore("synonyms");
// for (const [name, mastertag] of Object.entries(data.synonyms))
// {
// synonyms_store.add({"name": name, "mastertag": mastertag});
// }
// tag_autocomplete.synonyms = data.synonyms;
// count = data.tags.length + Object.keys(data.synonyms).length;
// console.log(`Updated db tags with ${count} items.`);
// if (document.getElementById(tag_autocomplete.DATALIST_ID))
// {
// setTimeout(() => tag_autocomplete.init_datalist(), 0);
// }
// }
// function load_stored_tags()
// {
// console.log("Loading stored db tags.");
// const load_transaction = tag_autocomplete.db.transaction(["tags", "synonyms"]);
// const tags_store = load_transaction.objectStore("tags");
// const tags_request = tags_store.getAll();
// tags_request.onsuccess = function(event)
// {
// for (row of event.target.result)
// {
// tag_autocomplete.tags.add(row["name"]);
// }
// }
// // const synonyms_transaction = tag_autocomplete.db.transaction(["synonyms"]);
// const synonyms_store = load_transaction.objectStore("synonyms");
// const synonyms_request = synonyms_store.getAll();
// synonyms_request.onsuccess = function(event)
// {
// for (row of event.target.result)
// {
// tag_autocomplete.synonyms[row["name"]] = row["mastertag"];
// }
// if (document.getElementById(tag_autocomplete.DATALIST_ID))
// {
// setTimeout(() => tag_autocomplete.init_datalist(), 0);
// }
// }
// }
tag_autocomplete.get_all_tags_callback =
function get_all_tags_callback(response)
{
if (response["meta"]["status"] == 304)
{
return;
}
if (response["meta"]["status"] == 200)
if (response["meta"]["status"] != 200)
{
tag_autocomplete.tagset = response["data"];
if (document.getElementById(tag_autocomplete.DATALIST_ID))
{
tag_autocomplete.init_datalist();
}
console.log(`Updated tagset contains ${tag_autocomplete.tagset.tags.length}.`);
return tag_autocomplete.tagset;
console.error(response);
return;
}
console.error(response);
}
tag_autocomplete.update_tagset =
function update_tagset()
{
console.log("Updating known tagset.");
const url = "/all_tags.json";
common.get(url, tag_autocomplete.update_tagset_callback);
// const server_updated = response.data.updated;
// const transaction = tag_autocomplete.db.transaction(["meta"]);
// const meta_store = transaction.objectStore("meta");
// const request = meta_store.get("updated");
// request.onsuccess = function(event)
// {
// if (event.target.result === undefined || event.target.result < server_updated)
// {
// update_stored_tags(response.data);
// }
// else
// {
// load_stored_tags();
// }
// }
tag_autocomplete.tags = new Set(response.data.tags);
tag_autocomplete.synonyms = response.data.synonyms;
setTimeout(() => tag_autocomplete.init_datalist(), 0);
return tag_autocomplete.tagset;
}
tag_autocomplete.on_pageload =
function on_pageload()
{
tag_autocomplete.update_tagset();
setTimeout(() => api.tags.get_all_tags(tag_autocomplete.get_all_tags_callback), 0);
tag_autocomplete.init_entry_with_tagname_replacements();
}
document.addEventListener("DOMContentLoaded", tag_autocomplete.on_pageload);

View file

@ -225,7 +225,6 @@ function my_clipboard_load_save_hook()
refresh_divs();
}
tag_autocomplete.init_datalist();
photo_clipboard.on_load_hooks.push(my_clipboard_load_save_hook);
photo_clipboard.on_save_hooks.push(my_clipboard_load_save_hook);

View file

@ -541,8 +541,6 @@ function move_hoverzoom(event)
photo_viewer.style.backgroundPosition=(-x)+"px "+(-y)+"px";
}
tag_autocomplete.init_datalist();
function autofocus_add_tag_box()
{
/*

View file

@ -655,7 +655,6 @@ function tag_input_hook_forbids()
tag_input_hook(this, inputted_forbids, "search_builder_forbids_inputted");
}
tag_autocomplete.init_datalist();
const input_musts = document.getElementById("search_builder_musts_input");
const ul_musts = input_musts.parentElement.parentElement;
const input_mays = document.getElementById("search_builder_mays_input");