chrome extension - best method of reducing load time while using content scripts

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-23 16:53:47

问题


I'm building a chrome extension that is supposed to look through an array of over 12,000 values and compare it to the webpages p tags, and if a value from the array is inside the p tag it should highlight the text and when hovered it should display some information. So, easy enough I suppose using content scripts but using "run_at": "document_end" made the webpage load 3 times slower, almost 10 seconds more to load with my extension. Obviously not ideal.

This is my content script code by the way:

jQuery(document).ready(function($) {

var $all_p = $("p");

$.each(arrayObj, function(key, value) {
      $all_p.highlight(key, {caseSensitive: true, className: 'highlight-882312', wordsOnly:true });
});

$('.highlight-882312').each(function() {    

    var currentKey = $(this).text();
    console.log(currentKey);

        //Create tooltip on hover.
        Tipped.create(this, "<iframe id='cardiFrame' src='https://mywebsite.com/word?q="+footballers[currentKey]+"'></iframe>", {
            skin: "white",
            hook: 'rightmiddle',
            maxWidth: 306,
            maxHeight: 365,
            background: '#eee',
        }); 

});
});

Anyway, this was way too slow for me, but I still wanted to build the extension so I thought I could send an array of all the p tags to my background/popup so that within the background/popup it would loop through to find the keywords and then display the keywords that matched inside the popup and send a message back to the content script of which keywords matches so that they could be highlighted. Would this reduce load time? Is this a good work around for my issue since an extra 10 second load time isn't ideal at all?

I'd appreciate any advice really.

Edit: arrayObj:

var arrayObj = {

"word1": 'word_word1',
"word2": 'word_word2',
"word3": 'word_word3',

// extra 12K lines...
}

Manifest.json:

My manifest is quite typical, but content script information is:

 "content_scripts": [
    {
      "matches": ["http://*/*", "https://*/*"],
      "css": ["styles.css", "tipped.css"],
      "js": ["jquery.min.js", "jquery-highlight1.js", "spinners.min.js", "tipped.js", "word.js", "script.js"],
      "run_at": "document_end"
    }
  ],

回答1:


Update http://jsfiddle.net/r4bnxemL/3/

This new approach is less complicated and it doesn't merge each word into one big regex. Instead it just uses asycn looping method using setTimeout trick.

var words = ['dolor', 'sit', 'odio'];

var ele = document.getElementById('text'),
    html = ele.innerHTML;


asycnIterator(words,
    function (word) {
        var reg = new RegExp('\\b' + word + '\\b', 'ig');
        html = html.replace(reg, '<span class="marked">' + word + '</span>');
    }, function () {
        ele.innerHTML = html;
});

function asycnIterator(arr, func, cb) {
    var i = 0;

    nextCall();

    function nextCall() {
        func(arr[i++]);
        if (i >= arr.length) {
            if (cb) cb();
            return;
        }
        setTimeout(nextCall, 1);
    }
}

First of all there are two things you could do first break the loop into tiny pieces it will probably make the whole process finish a bit in more time BUT it won't block everything else, Javascript single threaded so use event loop.

You can do it using setTimeout for example. (note will need to use callback pattern as it will return immediately, next line's execution wont wait for loop to finish)

var arr = [1,2,3....100000];
var i = 0 ;
nonBlockingAsycnLoop(); //will prints all values in console without blocking

function nonBlockingAsycnLoop() {
   console.log(arr[i++]);
   setTimeout(nonBlockingAsycnLoop,0);
}

Second thing you can do is make looking up faster. For that matter the more native method you use the better it's going to be. This is just my approach

  1. join all array elements into a string
  2. then search using them as regex
  3. store the indexes

This following function does that and invokes cb with list of all occurrences.

function returnOccurences(str, arr, cb) {
    var ele = null,
        index = 0,
        occurences = [],
        regexp = '\\b' + arr.join('\\b|\\b') + '\\b';

    getNextWord();
    function getNextWord() {
        ele = str.substr(index).match(new RegExp( regexp , 'i'));
        if (!ele) {
            cb(occurences);
            return;
        }
        occurences.push({i: ele.index, len: ele[0].length, word: ele[0]});
        index = ele[0].length + ele.index;
        setTimeout(getNextWord,0); //makes it non blocking
    }
}

String match function docs MDN LINK It if is not invoked with parameter g for regex than it return array with non enumerable properties which are index of the word found and input that contains the original text.

We can use index to parse further the string ahead after first match.



来源:https://stackoverflow.com/questions/30956709/chrome-extension-best-method-of-reducing-load-time-while-using-content-scripts

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!