Reputation: 989
I have the following function which replaces links in a contenteditable textarea. It works, but gets slow around 100 characters. How can I optimize this function to be faster?
function makeLinksFrom (str) {
var wordArray = str.replace(/(<([^>]+)>)/ig,"").split(' ');
var domainsArray = ['.com', '.net', '.co', '.ca', '.io', '.me'];
wordArray.forEach(function(word) {
domainsArray.forEach(function(domain) {
if(word.indexOf(domain) != -1 && word.substr(word.length - 6) == ' ') {
if(word.indexOf('http://') == -1) {
str = str.replace(word, '<a target="_blank" contenteditable="false" href="http://'+clean(word)+'">link</a> ');
} else {
str = str.replace(word, '<a target="_blank" contenteditable="false" href="'+clean(word)+'">link</a> ');
}
}
});
});
return str;
}
Upvotes: 1
Views: 105
Reputation: 3253
You need to split algorithm into two separate loops (not one in another), using a hash of words. It would look like (not tested, but you have an idea):
var hash = {};
var key;
var i;
for (i=0; i<wordArray.length; i++) {
for (var j=0; j<domainsArray.length; j++);
key = word[i] + "/" + domain[j];
hash[key] = key;
}
}
for (key in hash) {
word = hash[key].split('/')[0];
domain = hash[key].split('/')[1];
if (word.indexOf(domain) != -1 ...
....
....
}
Upvotes: 0
Reputation: 106
You do not have to check for each word repeatedly. All you need to do is put the words in the string in a hash and then create the hyperlinked word once for each of the cases. Then replace ONLY the words that have been changed. Here is how I would do it. Hope this helps.
function makeLinksFrom (str) {
var wordArray = str.replace(/(<([^>]+)>)/ig,"").split(' ');
var domainsArray = ['.com', '.net', '.co', '.ca', '.io', '.me'];
var positions = {};
wordArray.forEach(function(word){
var value = positions[word];
positions[word] = 1;
});
var keys = Object.keys(positions);
var cleanWord = {};
keys.forEach(function(key){
domainsArray.forEach(function(domain){
if(key.indexOf(domain) != -1 && key.substr(word.length - 6) == ' ') {
if(key.indexOf('http://') == -1){
cleanWord[key] = '<a target="_blank" contenteditable="false" href="http://'+clean(word)+'">link</a> ';
}else{
cleanWord[key] = '<a target="_blank" contenteditable="false" href="'+clean(word)+'">link</a> ';
}
}
});
});
keys.forEach(function(key){
if(key != cleanWord[key])
str = str.replace(key, cleanWord[key]);
});
return str;
}
In case you do not mind loosing the extra spaces you might want to replace the lower part of code to the following
keys.forEach(function(key){
domainsArray.forEach(function(domain){
if(key.indexOf(domain) != -1 && key.substr(word.length - 6) == ' ') {
if(key.indexOf('http://') == -1){
cleanWord[key] = '<a target="_blank" contenteditable="false" href="http://'+clean(word)+'">link</a> ';
}else{
cleanWord[key] = '<a target="_blank" contenteditable="false" href="'+clean(word)+'">link</a> ';
}
}else{
cleanWord[key] = word;
}
});
});
var newArr = [];
wordArray.forEach(function(word){
newArr.push(cleanWord[word]);
});
return newArr.join(" ");
Upvotes: 1
Reputation: 914
You can replace this lines
domainsArray.forEach(function(domain) {
if(word.indexOf(domain) != -1 && word.substr(word.length - 6) == ' ')
with a regular expression verification like:
if (work.match(/.+\\.(com|net|co|ca|io|me)/) != null && word.substr(word.length - 6) == ' ')
You will have much more speed with the same result!
Upvotes: 0