Arr = [] arr = new Array'den neden daha hızlıdır?


146

Bu kodu çalıştırdım ve aşağıdaki sonucu aldım. Neden []daha hızlı olduğunu merak ediyorum ?

console.time('using[]')
for(var i=0; i<200000; i++){var arr = []};
console.timeEnd('using[]')

console.time('using new')
for(var i=0; i<200000; i++){var arr = new Array};
console.timeEnd('using new')
  • kullanma []: 299ms
  • kullanma new: 363ms

Raynos sayesinde burada bu kodun bir karşılaştırması ve bir değişkeni tanımlamanın daha olası bir yolu var.

görüntü açıklamasını buraya girin


5
Jsperf ilginizi çekebilir .
Sivri


Yeni anahtar kelimeye dikkat edin. Bu, "lütfen daha az verimli ol" anlamına gelir. Hiçbir zaman mantıklı gelmez ve tarayıcının optimizasyon yapmaya çalışmak yerine normal örneklemeyi yapmasını gerektirir.
beatgammit

2
@kinakuta hayır. Her ikisi de eşit olmayan yeni nesneler yaratır. Demek istediğim [], new Array()kaynak kodu açısından eşdeğerdir , form ifadeleri döndürülen nesneler değil
Raynos

1
Evet, çok önemli değil. Ama bilmek isterim.
Mohsen

Yanıtlar:


195

Önceki cevapları daha da genişletiyoruz ...

Genel bir derleyici bakış açısından ve sanal makineye özgü optimizasyonları göz ardı ederek:

İlk olarak, kodu belirteceğimiz sözcüksel analiz aşamasından geçiyoruz.

Örnek olarak, aşağıdaki belirteçler üretilebilir:

[]: ARRAY_INIT
[1]: ARRAY_INIT (NUMBER)
[1, foo]: ARRAY_INIT (NUMBER, IDENTIFIER)
new Array: NEW, IDENTIFIER
new Array(): NEW, IDENTIFIER, CALL
new Array(5): NEW, IDENTIFIER, CALL (NUMBER)
new Array(5,4): NEW, IDENTIFIER, CALL (NUMBER, NUMBER)
new Array(5, foo): NEW, IDENTIFIER, CALL (NUMBER, IDENTIFIER)

Umarım bu size yeterli bir görselleştirme sağlamalıdır, böylece daha fazla (veya daha az) işlemin ne kadar gerekli olduğunu anlayabilirsiniz.

  1. Yukarıdaki belirteçlere dayanarak, ARRAY_INIT'in her zaman bir dizi üreteceğini biliyoruz. Bu nedenle basitçe bir dizi oluşturup onu dolduruyoruz. Belirsizliğe gelince, sözcük analizi aşaması, ARRAY_INIT'i bir nesne özelliği erişimcisinden (ör. obj[foo]) Veya dizeler / normal ifade değişmezleri (ör. "Foo [] bar" veya / [] /) içindeki parantezlerden ayırmıştır.

  2. Bu çok küçük ama aynı zamanda daha fazla tokenimiz var new Array. Dahası, henüz bir dizi oluşturmak istediğimiz tam olarak belli değil. "Yeni" belirteci görüyoruz, ama "yeni" ne? Daha sonra, yeni bir "Dizi" istediğimizi belirten IDENTIFIER belirtecini görürüz, ancak JavaScript sanal makineleri genellikle "yerel global nesneler" için bir IDENTIFIER jetonu ve jetonları ayırt etmez. Bu nedenle ...

  3. Bir IDENTIFIER belirteci ile her karşılaştığımızda kapsam zincirine bakmalıyız. Javascript VM'leri, "argümanlar" nesnesini, yerel olarak tanımlanmış değişkenleri vb. İçerebilen her yürütme bağlamı için bir "Aktivasyon nesnesi" içerir. Eğer onu Aktivasyon nesnesinde bulamazsak, genel kapsama ulaşana kadar kapsam zincirini aramaya başlarız. . Hiçbir şey bulunmazsa, bir ReferenceError.

  4. Değişken bildirimini bulduktan sonra, kurucuyu çağırırız. new Arrayörtük bir işlev çağrısıdır ve temel kural, işlev çağrılarının yürütme sırasında daha yavaş olmasıdır (bu nedenle statik C / C ++ derleyicileri "işlev satır içi yapmaya" izin verir - SpiderMonkey gibi JS JIT motorlarının anında yapması gerekir)

  5. ArrayYapıcı aşırı yüklü. Dizi yapıcısı yerel kod olarak uygulandığından bazı performans geliştirmeleri sağlar, ancak yine de bağımsız değişken uzunluğunu kontrol etmesi ve buna göre davranması gerekir. Dahası, yalnızca bir argüman sağlandığında, argümanın türünü daha fazla kontrol etmemiz gerekir. new Array ("foo") ["foo"] üretir, burada new Array (1) [undefined] üretir

Dolayısıyla, hepsini basitleştirmek için: dizi değişmezleriyle, VM bir dizi istediğimizi bilir; ile new Arraysanal makinenin new Array gerçekte ne yaptığını anlamak için fazladan CPU döngüleri kullanması gerekir .


a = new Array (1000); for (0'dan 999'a) {a [i] = i} a = [] 'den daha hızlı; for (0'dan 999'a) {a [i] = i} tahsis ek yükü olsa?
Y. Yoshii

Sadece bir deneme çalışması yaptım. new Array (n), dizinin boyutunu önceden bildiğiniz durumlarda daha hızlıdır jsperf.com/square-braces-vs-new-array
Y. Yoshii

27

Olası nedenlerden biri, new Arraybir ad araması gerektirmesidir Array(kapsamda bu ada sahip bir değişkene sahip olabilirsiniz), oysa []değildir.


4
Argümanları kontrol etmek de katkıda bulunabilir.
Leonid

Arrayhem bir argümanı hem de lençoklu argümanları hariç tutar . []Yalnızca birden çok argümanı kabul ettiği yerde . Ayrıca firefox testleri neredeyse hiç fark göstermiyor.
Raynos

Sanırım bunda bazı gerçekler var. OP'nin döngü testini bir IIFE'de çalıştırmak, performans üzerinde (nispeten) önemli bir etki yaratır . Dahil etmek var Array = window.Array, new Arraytestin performansını artırır .
user113716

Bunun doğru olduğunu düşünmüyorum çünkü bu console.time ('more vars new'); for (var i = 0; i <200000; i ++) {var arr = new Array ()}; console.timeEnd ('daha fazla değişken'); daha fazla değişken yeni: 390ms ve bu console.time ('daha fazla değişken yeni'); var myOtherObject = {}, myOtherArray = []; for (var i = 0; i <200000; i ++) {var arr = new Array ()}; console.timeEnd ('daha fazla değişken'); daha fazla değişken yeni: 369ms Aynı anda döner
Mohsen

2

İyi soru. İlk örnek, bir dizi değişmezi olarak adlandırılır. Pek çok geliştirici arasında dizi oluşturmanın tercih edilen yolu budur. Performans farkının nedeni, yeni Array () çağrısının bağımsız değişkenlerinin kontrol edilmesi ve ardından değişmez değerin doğrudan bir dizi oluşturması sırasında nesnenin oluşturulması olabilir.

Performanstaki nispeten küçük fark, bence bu noktayı destekliyor. Bu arada aynı testi Object ve nesne değişmezi {} ile de yapabilirsiniz.


1

Bu biraz mantıklı

Nesnelerin değişmez değerleri, birçok özelliği destekleyen ancak yine de kodumuzun uygulayıcıları için nispeten basit hale getiren kod yazmamızı sağlar. Yapıcıları doğrudan çağırmaya veya işlevlere vb. İletilen argümanların doğru sırasını korumaya gerek yok

http://www.dyn-web.com/tutorials/obj_lit.php


1

Ayrıca ilginçtir, dizinin uzunluğu önceden biliniyorsa (öğeler oluşturulduktan hemen sonra eklenecektir), belirli bir uzunluğa sahip bir dizi oluşturucunun kullanımı son Google Chrome 70+ üzerinde çok daha hızlıdır .

  • " yeni Dizi ( % ARR_LENGTH% ) " -% 100 (daha hızlı) !

  • " [] " -% 160-170 (daha yavaş)

Önlemlerin sonuçlarını içeren grafik.

Test burada bulunabilir - https://jsperf.com/small-arr-init-with-known-length-brackets-vs-new-array/2

Not: bu sonuç Google Chrome v.70 + üzerinde test edilmiştir ; içinde Firefox V.70 IE ve de neredeyse eşit varyantları.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.