𝗥𝗲𝘀𝗲𝗮𝗿𝗰𝗵 𝗔𝗻𝗱 𝗥𝗲𝘀𝘂𝗹𝘁𝘀
Gerçekler için, jsperf'de bir performans testi ve konsoldaki bazı şeylerin kontrol edilmesi gerçekleştirilir. Araştırma için irt.org web sitesi kullanılmıştır. Aşağıda, bir araya getirilen tüm bu kaynakların bir koleksiyonu ve altta bir örnek işlev bulunmaktadır.
╔═══════════════╦══════╦═════════════════╦════════ ═══════╦═════════╦══════════╗
║ Yöntemi
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║ mOps / Saniye ║179 ║104 ║ 76 ║ 81 ║28 ║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║ Seyrek diziler ║Evet! ║Sadece dilimlenmiş ║ hayır ║ Belki 2 ║no ║
║ seyrek tutulmuş ║ ║array (1. arg) ║ ║ ║ ║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║ Destek ║MSIE 4║MSIE 5.5 ║ MSIE 5.5 ║ MSIE 4 ║ Kenar 12 ║
║ ( kaynak ) ║NNav 4║NNav 4.06 ║ NNav 4.06 ║ NNav 3 ║ MSIE NNav ║
╠═══════════════╬══════╬═════════════════╬════════ ═══════╬═════════╬══════════╣
║ Dizi benzeri eylemler║ hayır nSadece itti ║ EVET! ║ EVET! HaveEğer varsa ║
Bir dizi ║ ║array (2 arg) ║ ║ ║iterator ║like 1 ║
╚═══════════════╩══════╩═════════════════╩════════ ═══════╩═════════╩══════════╝
1 Dizi benzeri bir nesnenin Symbol.iterator özelliği yoksa ,
yaymak bir istisna atar.
2 Koda bağlıdır. Aşağıdaki örnek kod "EVET" seyrekliği korur.
function mergeCopyTogether(inputOne, inputTwo){
var oneLen = inputOne.length, twoLen = inputTwo.length;
var newArr = [], newLen = newArr.length = oneLen + twoLen;
for (var i=0, tmp=inputOne[0]; i !== oneLen; ++i) {
tmp = inputOne[i];
if (tmp !== undefined || inputOne.hasOwnProperty(i)) newArr[i] = tmp;
}
for (var two=0; i !== newLen; ++i, ++two) {
tmp = inputTwo[two];
if (tmp !== undefined || inputTwo.hasOwnProperty(two)) newArr[i] = tmp;
}
return newArr;
}
Yukarıda görüldüğü gibi, Concat'ın neredeyse her zaman hem performans hem de yedek dizilerin seyrekliğini koruyabilme yolu olduğunu iddia ediyorum. Daha sonra, dizi beğenileri (örneğin DOMNodeLists gibi document.body.children
) için, for döngüsünü kullanmanızı tavsiye ederim çünkü hem en yüksek 2. performans hem de seyrek dizileri tutan tek diğer yöntemdir. Aşağıda, karışıklığı gidermek için seyrek diziler ve dizi beğenileriyle kastedilen şeyleri hızla ele alacağız.
𝗧𝗵𝗲 𝗙𝘂𝘁𝘂𝗿𝗲
İlk başta, bazı insanlar bunun bir fluke olduğunu düşünebilir ve tarayıcı satıcıları sonunda Array.prototype.push'u Array.prototype.concat'i yenecek kadar hızlı olacak şekilde optimize etmeye çalışacaklardır. YANLIŞ! Array.prototype.concat her zaman daha hızlı olacaktır (prensip olarak en azından) çünkü veriler üzerinde basit bir kopyala-yapıştır. Aşağıda, 32 bit dizi uygulamasının nasıl görünebileceğine dair basitleştirilmiş ikna-görsel bir diyagram bulunmaktadır (lütfen gerçek uygulamaların çok daha karmaşık olduğunu unutmayın)
Bayt ║ Burada veriler
═════╬═══════════
0x00 ║ int nonNumericPropertiesLength = 0x00000000
0x01 ║ age.
0x02 id age.
0x03 id age
0x00 ║ int uzunluğu = 0x00000001
0x01 ║ age.
0x02 id age.
0x03 id age
0x00 ║ int valueIndex = 0x00000000
0x01 ║ age.
0x02 id age.
0x03 id age
0x00 ║ int valueType = JS_PRIMITIVE_NUMBER
0x01 ║ age.
0x02 id age.
0x03 id age
0x00 ║ uintptr_t valuePointer = 0x38d9eb60 (veya bellekte olduğu her yerde)
0x01 ║ age.
0x02 id age.
0x03 id age
Yukarıda görüldüğü gibi, böyle bir şeyi kopyalamak için yapmanız gereken tek şey bayt için bayt kopyalamak kadar basittir. Array.prototype.push.apply ile, veriler üzerinde basit bir kopyala-yapıştırdan çok daha fazlasıdır. ".Apply" dizideki her dizini kontrol etmeli ve Array.prototype.push'a geçirmeden önce bir dizi argümana dönüştürmelidir. Daha sonra, Array.prototype.push her seferinde daha fazla bellek ayırmalıdır ve (bazı tarayıcı uygulamaları için) seyreklik için bazı konum arama verilerini bile yeniden hesaplayabilir.
Bunu düşünmenin alternatif bir yolu şudur. Birinci kaynak dizisi, birlikte zımbalanmış büyük bir kağıt yığınıdır. İkinci kaynak dizisi de bir başka büyük kağıt yığınıdır. Senin için daha hızlı olur mu
- Mağazaya gidin, her kaynak dizinin bir kopyası için gerekli kağıdı satın alın. Ardından, her kaynak dizisi yığınını bir fotokopi makinesinden geçirin ve elde edilen iki kopyayı birlikte zımbalayın.
- Mağazaya gidin, ilk kaynak dizinin tek bir kopyası için yeterli kağıdı satın alın. Ardından, kaynak diziyi boş kağıt noktalarının doldurulmasını sağlayarak yeni kağıda el ile kopyalayın. Ardından, mağazaya geri dönün, ikinci kaynak dizisi için yeterli kağıt satın alın. Ardından, ikinci kaynak diziyi gözden geçirin ve kopyada boş boşluk kalmamasını sağlarken kopyalayın. Ardından, kopyalanan tüm kağıtları birlikte zımbalayın.
Yukarıdaki benzetmede # 1 seçeneği Array.prototype.concat'i, # 2 ise Array.prototype.push.apply'yi temsil eder. Bunu, sadece katı diziler yerine seyrek diziler üzerindeki yöntemleri test ettiği için farklı bir JSperf ile test edelim. Bunu burada bulabilirsiniz .
Bu nedenle, bu özel kullanım durumu için performansın geleceğinin Array.prototype.push'ta değil, daha çok Array.prototype.concat'te yattığını söylüyorum.
𝗖𝗹𝗮𝗿𝗶𝗳𝗶𝗰𝗮𝘁𝗶𝗼𝗻𝘀
𝗦𝗽𝗮𝗿𝗲 𝗔𝗿𝗿𝗮𝘆𝘀
Dizinin belirli üyeleri eksik olduğunda. Örneğin:
// This is just as an example. In actual code,
// do not mix different types like this.
var mySparseArray = [];
mySparseArray[0] = "foo";
mySparseArray[10] = undefined;
mySparseArray[11] = {};
mySparseArray[12] = 10;
mySparseArray[17] = "bar";
console.log("Length: ", mySparseArray.length);
console.log("0 in it: ", 0 in mySparseArray);
console.log("arr[0]: ", mySparseArray[0]);
console.log("10 in it: ", 10 in mySparseArray);
console.log("arr[10] ", mySparseArray[10]);
console.log("20 in it: ", 20 in mySparseArray);
console.log("arr[20]: ", mySparseArray[20]);
Alternatif olarak, javascript yedek dizileri kolayca başlatmanıza izin verir.
var mySparseArray = ["foo",,,,,,,,,,undefined,{},10,,,,,"bar"];
𝗔𝗿𝗿𝗮𝘆-𝗟𝗶𝗸𝗲𝘀
Dizi benzeri, en az length
özelliği olan ancak new Array
veya ile başlatılmamış bir nesnedir []
. Örneğin, aşağıdaki nesneler dizi benzeri olarak sınıflandırılır.
{0: "foo", 1: "bar", uzunluk: 2}
document.body.children
yeni Uint8Array (3)
- Bu, diziye benzer çünkü bir (n) (yazılan) dizi olmasına rağmen, onu bir diziye zorlamak yapıcıyı değiştirir.
(function () {return argümanları}) ()
Dizi beğenilerini dilim gibi dizilere zorlayan bir yöntem kullanarak neler olduğunu gözlemleyin.
var slice = Array.prototype.slice;
// For arrays:
console.log(slice.call(["not an array-like, rather a real array"]));
// For array-likes:
console.log(slice.call({0: "foo", 1: "bar", length:2}));
console.log(slice.call(document.body.children));
console.log(slice.call(new Uint8Array(3)));
console.log(slice.call( function(){return arguments}() ));
- NOT: Performans nedeniyle işlev bağımsız değişkenlerinde dilim çağırmak kötü bir uygulamadır.
Olmayan bir yöntemi kullanarak ne olur gözlemleyin değil concat gibi diziler içine dizisi-sever zorlamak.
var empty = [];
// For arrays:
console.log(empty.concat(["not an array-like, rather a real array"]));
// For array-likes:
console.log(empty.concat({0: "foo", 1: "bar", length:2}));
console.log(empty.concat(document.body.children));
console.log(empty.concat(new Uint8Array(3)));
console.log(empty.concat( function(){return arguments}() ));