Add: improve import performance (#547)
* Add: implement db putMany * Fix: putMany returns a list of ids
This commit is contained in:
		
							parent
							
								
									8291da0bb5
								
							
						
					
					
						commit
						5646b8a0d9
					
				| 
						 | 
				
			
			@ -17,6 +17,7 @@ window.API_METHODS = Object.assign(window.API_METHODS || {}, {
 | 
			
		|||
  getStyle: styleManager.get,
 | 
			
		||||
  getStylesByUrl: styleManager.getStylesByUrl,
 | 
			
		||||
  importStyle: styleManager.importStyle,
 | 
			
		||||
  importManyStyles: styleManager.importMany,
 | 
			
		||||
  installStyle: styleManager.installStyle,
 | 
			
		||||
  styleExists: styleManager.styleExists,
 | 
			
		||||
  toggleStyle: styleManager.toggleStyle,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -74,41 +74,50 @@ const db = (() => {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  function dbExecIndexedDB(method, ...args) {
 | 
			
		||||
    return new Promise((resolve, reject) => {
 | 
			
		||||
      Object.assign(indexedDB.open('stylish', 2), {
 | 
			
		||||
        onsuccess(event) {
 | 
			
		||||
          const database = event.target.result;
 | 
			
		||||
    return open().then(database => {
 | 
			
		||||
      if (!method) {
 | 
			
		||||
            resolve(database);
 | 
			
		||||
          } else {
 | 
			
		||||
            const transaction = database.transaction(['styles'], 'readwrite');
 | 
			
		||||
        return database;
 | 
			
		||||
      }
 | 
			
		||||
      if (method === 'putMany') {
 | 
			
		||||
        return putMany(database, ...args);
 | 
			
		||||
      }
 | 
			
		||||
      const mode = method.startsWith('get') ? 'readonly' : 'readwrite';
 | 
			
		||||
      const transaction = database.transaction(['styles'], mode);
 | 
			
		||||
      const store = transaction.objectStore('styles');
 | 
			
		||||
            try {
 | 
			
		||||
              Object.assign(store[method](...args), {
 | 
			
		||||
                onsuccess: event => resolve(event, store, transaction, database),
 | 
			
		||||
                onerror: reject,
 | 
			
		||||
      return storeRequest(store, method, ...args);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    function storeRequest(store, method, ...args) {
 | 
			
		||||
      return new Promise((resolve, reject) => {
 | 
			
		||||
        const request = store[method](...args);
 | 
			
		||||
        request.onsuccess = resolve;
 | 
			
		||||
        request.onerror = reject;
 | 
			
		||||
      });
 | 
			
		||||
            } catch (err) {
 | 
			
		||||
              reject(err);
 | 
			
		||||
    }
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        onerror(event) {
 | 
			
		||||
          console.warn(event.target.error || event.target.errorCode);
 | 
			
		||||
          reject(event);
 | 
			
		||||
        },
 | 
			
		||||
        onupgradeneeded(event) {
 | 
			
		||||
 | 
			
		||||
    function open() {
 | 
			
		||||
      return new Promise((resolve, reject) => {
 | 
			
		||||
        const request = indexedDB.open('stylish', 2);
 | 
			
		||||
        request.onsuccess = () => resolve(request.result);
 | 
			
		||||
        request.onerror = reject;
 | 
			
		||||
        request.onupgradeneeded = event => {
 | 
			
		||||
          if (event.oldVersion === 0) {
 | 
			
		||||
            event.target.result.createObjectStore('styles', {
 | 
			
		||||
              keyPath: 'id',
 | 
			
		||||
              autoIncrement: true,
 | 
			
		||||
            });
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
        };
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function putMany(database, items) {
 | 
			
		||||
      const transaction = database.transaction(['styles'], 'readwrite');
 | 
			
		||||
      const store = transaction.objectStore('styles');
 | 
			
		||||
      return Promise.all(items.map(item => storeRequest(store, 'put', item)));
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function dbExecChromeStorage(method, data) {
 | 
			
		||||
    const STYLE_KEY_PREFIX = 'style-';
 | 
			
		||||
    switch (method) {
 | 
			
		||||
| 
						 | 
				
			
			@ -118,17 +127,33 @@ const db = (() => {
 | 
			
		|||
 | 
			
		||||
      case 'put':
 | 
			
		||||
        if (!data.id) {
 | 
			
		||||
          return getAllStyles().then(styles => {
 | 
			
		||||
            data.id = 1;
 | 
			
		||||
            for (const style of styles) {
 | 
			
		||||
              data.id = Math.max(data.id, style.id + 1);
 | 
			
		||||
            }
 | 
			
		||||
          return getMaxId().then(id => {
 | 
			
		||||
            data.id = id + 1;
 | 
			
		||||
            return dbExecChromeStorage('put', data);
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
        return chromeLocal.setValue(STYLE_KEY_PREFIX + data.id, data)
 | 
			
		||||
          .then(() => (chrome.runtime.lastError ? Promise.reject() : data.id));
 | 
			
		||||
 | 
			
		||||
      case 'putMany': {
 | 
			
		||||
        const newItems = data.filter(i => !i.id);
 | 
			
		||||
        const doPut = () =>
 | 
			
		||||
          chromeLocal.set(data.reduce((o, item) => {
 | 
			
		||||
            o[STYLE_KEY_PREFIX + item.id] = item;
 | 
			
		||||
            return o;
 | 
			
		||||
          }, {}))
 | 
			
		||||
            .then(() => data.map(d => ({target: {result: d.id}})));
 | 
			
		||||
        if (newItems.length) {
 | 
			
		||||
          return getMaxId().then(id => {
 | 
			
		||||
            for (const item of newItems) {
 | 
			
		||||
              item.id = ++id;
 | 
			
		||||
            }
 | 
			
		||||
            return doPut();
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
        return doPut();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      case 'delete':
 | 
			
		||||
        return chromeLocal.remove(STYLE_KEY_PREFIX + data);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -150,5 +175,17 @@ const db = (() => {
 | 
			
		|||
        return styles;
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function getMaxId() {
 | 
			
		||||
      return getAllStyles().then(styles => {
 | 
			
		||||
        let result = 0;
 | 
			
		||||
        for (const style of styles) {
 | 
			
		||||
          if (style.id > result) {
 | 
			
		||||
            result = style.id;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        return result;
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
})();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,6 +55,7 @@ const styleManager = (() => {
 | 
			
		|||
    editSave,
 | 
			
		||||
    findStyle,
 | 
			
		||||
    importStyle,
 | 
			
		||||
    importMany,
 | 
			
		||||
    toggleStyle,
 | 
			
		||||
    setStyleExclusions,
 | 
			
		||||
    getAllStyles, // used by import-export
 | 
			
		||||
| 
						 | 
				
			
			@ -138,6 +139,18 @@ const styleManager = (() => {
 | 
			
		|||
      .then(newData => handleSave(newData, 'import'));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function importMany(items) {
 | 
			
		||||
    return db.exec('putMany', items)
 | 
			
		||||
      .then(events => {
 | 
			
		||||
        for (let i = 0; i < items.length; i++) {
 | 
			
		||||
          if (!items[i].id) {
 | 
			
		||||
            items[i].id = events[i].target.result;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        return Promise.all(items.map(i => handleSave(i, 'import')));
 | 
			
		||||
      });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function installStyle(data, reason = null) {
 | 
			
		||||
    const style = styles.get(data.id);
 | 
			
		||||
    if (!style) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -126,13 +126,20 @@ function importFromString(jsonString) {
 | 
			
		|||
      oldStyles.map(style => [style.id, style]));
 | 
			
		||||
    oldStylesByName = json.length && new Map(
 | 
			
		||||
      oldStyles.map(style => [style.name.trim(), style]));
 | 
			
		||||
    return Promise.all(json.map((item, i) => {
 | 
			
		||||
 | 
			
		||||
    const items = [];
 | 
			
		||||
    json.forEach((item, i) => {
 | 
			
		||||
      const info = analyze(item, i);
 | 
			
		||||
      if (info) {
 | 
			
		||||
        return API.importStyle(item)
 | 
			
		||||
          .then(style => updateStats(style, info));
 | 
			
		||||
        items.push({info, item});
 | 
			
		||||
      }
 | 
			
		||||
    }));
 | 
			
		||||
    });
 | 
			
		||||
    return API.importManyStyles(items.map(i => i.item))
 | 
			
		||||
      .then(styles => {
 | 
			
		||||
        for (let i = 0; i < styles.length; i++) {
 | 
			
		||||
          updateStats(styles[i], items[i].info);
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
  })
 | 
			
		||||
    .then(done);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user