String concatenation versus array.join() in JavaScript

To answer a question on StackOverflow, I made an experiment which actually qualifies for a separate blog post.

So, I compared the speed of str1+str2 concatenation and array.push(str1, str2).join() methods. The code I used was quite simple:

var iIterations =800000;
var d1 = (new Date()).valueOf();
str1 = "";
for (var i = 0; i<iIterations; i++) str1 = str1 + Math.random().toString();
var d2 = (new Date()).valueOf();
log("Time (strings): " + (d2-d1));

var d3 = (new Date()).valueOf();
arr1 = [];
for (var i = 0; i<iIterations; i++)arr1.push(Math.random().toString());
var str2 = arr1.join("");
var d4 = (new Date()).valueOf();
log("Time (arrays): " + (d4-d3));

I tested it in IE8 and FireFox 3.5.5, both on a Windows 7 x64.

In the beginning I tested on small number of iterations (some hundred, some thousand items). The results were unpredictable (sometimes string concatenation took 0 milliseconds, sometimes it took 16 milliseconds, the same for array joining).

When I increased the count to 50’000, the results were different in different browsers – in IE the string concatenation was faster (94 milliseconds) and join was slower(125 milliseconds), while in Firefox the array join was faster (113 milliseconds) than string joining (117 milliseconds).

Then I increased the count to 500’000. Now the array.join() was slower than string concatenation in both browsers: string concat 937ms in IE, 1155 ms in Firefox, array join 1265 in IE, 1207 in Firefox.

Maximum iteration count I could test in IE without having “the script is taking too long to execute” was 850’000. Then IE was 1593 for string concatenation and 2046 for array join, Firefox had 2101 for string concatenation and 2249 for array join.

Results – if the number of iterations is small, you can try to use array.join(), as it might be faster in Firefox. When the number increases, the string1+string2 method is faster.

UPDATE
I performed the test on IE6 (WindowsXP). The process stopped to respond immediately and never ended, if I tried the test on more than 100’000 iterations. On 40’000 iterations the results were

Time (strings): 59175 ms
Time (arrays): 220 ms

This means – if you need to support IE6, choose array.join() which is way faster than string concatenation.

Web izstrādātātāju bookmarklets

Izstrādātājot lietas tīmeklim, reizēm gribas pārliecību, ka lapa tiek tiešām pieprasīta par jaunu no servera, nevis izmantota IExplorer (vai citam pārlūkam pēc izvēles) pieejama kešota versija.

Parasti ar šo vēlmi tieku galā, pierakstot URLim galā kaut ko līdzīgu “&bubu”.
Nupat uzrakstīju bookmarkletu, kurš dara ko līdzīgu – ja URLī nav parametra TmpPart, tad to pieliek, ja tāds jau ir, tad tam piekabina galā kādus papildus burtus.

Bookmarkleta teksts (salauzts pa rindām, savelciet kopā, lai darbotos):

javascript:(function(){
    var sL = document.location+'';
    var s="";
        if (sL.indexOf('?')==-1) 
            s = sL + "?TmpPart=x"; 
        else 
            if (sL.indexOf('TmpPart=')==-1) 
                s=sL+"&TmpPart=x"; 
            else 
                s = sL.replace(/(TmpPart=)(x+)/g,"$1$2x");
    document.location=s;
    }())

Iexplorer ContextMenu

Attiecībā uz tīmekļa sistēmu drošību ir teiciens, ka 100% droša sistēma būs 0% lietojama. Tātad, jo drošāk, jo neērtāk. Tā kā pēdējā laikā ir populāri dažādi phishing pasākumi, arī .lv internetbankas cenšas panākt arvien augstāku savu pakalpojumu drošību. Līdz ar to ne tik vien tiek izmantoti SSL pieslēgumi, nesaprotami lietotāja vārdi un pieprasītas garas un sarežģītas paroles, bet arī tiek lietotas kodu kartes (tās ir tādas kartiņas ar daudzām burtu/skaitļu virknītēm, katrai virknītei savs numuriņš. Pieslēdzoties e-bankai tiek pieprasīts ievadīt kādu no virknītēm, piemēram septīto pēc kārtas).

Ideja jau skaista, bet lietojamība… katru reizi, kad gribi apskatīties, kā tavā kontā vēl joprojām ir tikai 3 santīmi, tev jāmeklē karte, uz tās jāmeklē kodi, tie “jāpārdrukā” u.t.t.

Šeit pastāstīšu risinājumu, kā papildināt Internet Explorer contextMenu ar savu funkciju, kas atgriež vajadzīgo kodu kartes ierakstu.

“Gudrību” iešujam JavaScript koda gabalā, kurš pārbauda, vai pārlūkprogramma atrodas manas internetbankas lapā un pēc tam no kodu kartes atrod vajadzīgo kodu un to iekopē “starpliktuvē” (clipboard).

< SCRIPT LANGUAGE="JavaScript">
var parentwin = external.menuArguments;
var doc = parentwin.document;
var sel = doc.selection;
var rng = sel.createRange();
var iNum = 0;

//vai esam nokļuvuši e-bankā
if (external.menuArguments.location.host=="mana.e-banka.lv") {

    //ja jā, tad uzstāda kodu kartes vērtības
    var myCodes = new Array("*****", "*****", "*****", "*****", 
                             "*****", "*****", "*****", "*****",
                             "*****", "*****", "*****", "*****", 
                             "*****", "*****", "*****", "*****");
    //kas iezīmēts browser logā?
    if (rng.text!="")
        iNum = rng.text*1;
        //ja iezīmēts skaitlis, mēģina nolasīt kodu
        if (!isNaN(iNum)) 
            window.clipboardData.setData("Text", myCodes[iNum-1]);
        else 
            alert("Nav iezīmēts skaitlis!") 
    }
else {
   alert("Šobrīd Tu neesi bankas lapā!");
}
< /SCRIPT>

Šādu skriptu saglabājam .htm failā uz cietā diska. Piemēram iekš, c:\i\banka.htm Pēc tam veram vaļā RegEdit, un meklējam šādu zaru: HKEYCURRENTUSER\Software\Microsoft\Internet Explorer\MenuExt Iespējams, tur jau priekšā būs kādi ieraksti no Tilde vai kāda cita programmatūras izstrādātāja, kurš savus produktus integrē MSIE. Pievienojam jaunu atslēgu, tās nosaukums būs redzams konteksta dialogā. Piemēram, es pievienoju atslēgu ar nosaukumu “&KoduKarte”. Atslēgas Default vērtību uzstāda uz .htm failu, kurā saglabāts skripts, tas ir manā gadījumā, c:\i\banka.htm Papildus tam, atslēgā pievieno DWORD vērtību Contexts, kurā ierakstām “10”. Tas nozīmē, ka funkcija kontekstu dialogā būs redzama tikai tad, kad ir iezīmēts teksts. Eksportējot no reģistra, atslēga izskatās šādi:

[HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt\&KoduKarte]
@="c:\\i\\banka.htm"
"Contexts"=dword:00000010

Pēc tam atliek atvērt jaunu InternetExplorer logu un tajā jau būs pieejama jaunā funkcija. Tikai tad, kad būs atvērta internetbankas lapa, tikai tad, kad būs iezīmēts teksts un nospiesta peles labā poga.

Vēlreiz brīdinu, ka šādi darīt nav labi un pavisam noteikti IR SLIKTI, jo šādā veidā Tu samazini Tavas bankas izveidotās drošības sistēmas drošības līmeni. Jo gadījumā, ja kādam citam būs pieeja Tava datora cietajam diskam, viņš(a) varēs nolasīt failu, kur glabājas kodi un tad viņam(ai) atliks TIKAI UZMINĒT TAVU LIETOTĀJA VĀRDU UN PAROLI, lai iekļūtu bankas lapā!

UzKlikšķa

Bieži vien gribas darīt šādi:

<a href="javascript:ShowPic('image1.jpg')">skatīt bildi</a>

Tas ir, lai parādītu bildīti, izsaucam JavaScript funkciju, kurai parametros nododam attēla nosaukumu. Risinājums labi darbosies itin daudziem lietotājiem, tomēr viegli pārliecināties, ka rezultāts nebūs sasniegts, kad pārlūkā atslēgsim JavaScript atbalstu. Turklāt – javascript: lietošana hipersaites href atribūta vērtībā ir nekorekta – šajā atribūtā jānorāda URI shēmai atbilstoša vērtība. javascript: ir pseidoprotokols, līdzīgi kā about: vai chrome:.

Daži problēmu risinātu šādi:

<a href="#" onclick="ShowPic('image1.jpg')">skatīt bildi</a>

Diemžēl šāds risinājums vēl joprojām nepalīdzēs gadījumā, kad pārlūkā atslēgsim JavaScript atbalstu. Mēģināsim lietot <a> birku tam, kam tā domāta – saites norādīšanai. To varam izdarīt šādi

<a href="image1.jpg" onclick="ShowPic('image1.jpg');return false">skatīt bildi</a>

Nu jau izskatās itin labi. Tie pārlūki, kas neatbalsta JavaScript vai arī kam izslēgts javascript, atvērs pašu bildi, bet pārējie izpildīs funkciju ShowPic(), kas droši vien parāda attēlu citā un skaistākā veidā. Papildus pievienotais “return false” nodrošina to, ka pēc funkcijas izpildes notikums “ir ticis uzklikšķināts uz hipersaites” tiek atcelts, tādējādi pārlūks neatvērs adresi, kas aprakstīta href atribūtā.

Tomēr – ak vai, ak vai – šāds dokuments, kam DOCTYPE norādīts XHTML 1.0 Strict negrib "validēties" Tā kā XHTML standarts paredz striktu nodalījumu starp dokumenta saturu (pats XHTML), tā izkārtojumu (CSS stili) un prezentāciju (piekārtotie skripti), tad atribūts onclick vairs nav pieļaujams A elementam.

Tāpēc darām šādi: pašā XHTML dokumentā iekļaujam tikai šādu saiti:

<a href="image1.jpg" class="PictureLink">skatīt bildi</a>

Savukārt dokumentam piekārtotajā skriptu failā piesaistām šim elementam notikumu ķērāju:

//pēc dokumenta pilnas ielādes, izsauc funkciju, kas "salabo" saites
document.body.onload=InitPictureLinks;

//funkcija iziet cauri visām dokumenta hipersaitēm un vajadzīgās no tām "salabo" function InitPictureLinks(){ var oLinks; //šī būs visu hipersaišu kolekcija

//izmanto DOM funkciju, lai nolasītu visas hipersaites oLinks = document.getElementsByTagName("A");

for (var i=0;i<olinks .length;i++){ //apstrādā tikai tos A elementus, kuru klase ir PictureLink if (oLinks[i].className=="PictureLink") addLink(oLinks[i];) } }

//piesaista notikumu ķērāju "onclick". //pēc klikšķa tiek izsaukta funkcija ShowPic, parametros //nododot href atribūtā uzstādīto vērtību un atgriezts false, //lai atceltu klikšķa notikumu function addLink(opLink){ opLink.onclick = function(){ShowPic(opLink.href);return false}; }