Apakah loop sangat cepat terbalik?

268

Saya sudah mendengar ini beberapa kali. Apakah loop JavaScript benar-benar lebih cepat saat menghitung mundur? Jika demikian, mengapa? Saya telah melihat beberapa contoh test suite yang menunjukkan bahwa loop terbalik lebih cepat, tetapi saya tidak dapat menemukan penjelasan mengapa!

Saya berasumsi itu karena loop tidak lagi harus mengevaluasi properti setiap kali memeriksa untuk melihat apakah sudah selesai dan hanya memeriksa terhadap nilai numerik akhir.

Yaitu

for (var i = count - 1; i >= 0; i--)
{
  // count is only evaluated once and then the comparison is always on 0.
}
djdd87
sumber
6
hehe. itu akan memakan waktu tak terbatas. coba saya
StampedeXV
5
forLoop mundur lebih cepat karena variabel kontrol loop atas-terikat (hehe, -batas) tidak harus didefinisikan atau diambil dari objek; ini adalah nol konstan.
Josh Stodola
88
Tidak ada perbedaan nyata . Konstruksi loop asli akan selalu sangat cepat . Jangan khawatir tentang kinerja mereka.
James Allardice
24
@Afshin: Untuk pertanyaan seperti ini, tolong tunjukkan artikel yang Anda maksud.
Lightness Races di Orbit
22
Ada perbedaan terutama penting untuk perangkat yang sangat low-end dan bertenaga baterai. Perbedaannya adalah bahwa dengan i-- Anda membandingkan dengan 0 untuk akhir loop, sedangkan dengan i ++ Anda membandingkan dengan angka> 0. Saya percaya perbedaan kinerja adalah sekitar 20 nanodetik (sekitar kapak cmp, kapak 0 vs cmp) , bx) - yang tidak lain adalah jika Anda mengulang ribuan kali per detik, mengapa tidak memiliki 20 nanodetik untuk setiap :)
luben

Jawaban:

903

Bukan itu i--lebih cepat daripada i++. Sebenarnya, keduanya sama-sama cepat.

Apa yang membutuhkan waktu dalam loop menanjak adalah mengevaluasi, untuk masing-masing i, ukuran array Anda. Dalam lingkaran ini:

for(var i = array.length; i--;)

Anda mengevaluasi .lengthhanya sekali, ketika Anda menyatakan i, sedangkan untuk loop ini

for(var i = 1; i <= array.length; i++)

Anda mengevaluasi .lengthsetiap kali Anda menambah i, ketika Anda memeriksa apakah i <= array.length.

Dalam kebanyakan kasus Anda bahkan tidak perlu khawatir tentang optimasi semacam ini .

alestanis
sumber
23
apakah layak untuk memperkenalkan variabel untuk array.length dan menggunakannya di for for loop's head?
ragatskynet
39
@ragatskynet: Tidak, kecuali jika Anda mengatur tolok ukur dan ingin membuat poin.
Jon
29
@ragatskynet Tergantung: apakah akan lebih cepat untuk mengevaluasi .lengthbeberapa kali atau untuk mendeklarasikan dan mendefinisikan variabel baru? Dalam kebanyakan kasus, ini adalah optimasi prematur (dan salah), kecuali Anda lengthsangat mahal untuk mengevaluasi.
alestanis
10
@ Dr.Dredel: Ini bukan perbandingan - ini evaluasi. 0lebih cepat untuk mengevaluasi daripada array.length. Yah, seharusnya.
Lightness Races di Orbit
22
Yang perlu disebutkan adalah bahwa kita berbicara tentang bahasa yang ditafsirkan seperti Ruby, Python. Bahasa yang dikompilasi misalnya Java memiliki optimisasi pada tingkat kompiler yang mana akan "menghaluskan" perbedaan-perbedaan ini ke titik yang tidak masalah apakah .lengthdalam deklarasi for loopatau tidak.
Haris Krajina
198

Orang ini membandingkan banyak loop di javascript, di banyak browser. Ia juga memiliki ruang uji sehingga Anda dapat menjalankannya sendiri.

Dalam semua kasus (kecuali saya melewatkan satu di baca saya) loop tercepat adalah:

var i = arr.length; //or 10
while(i--)
{
  //...
}
Tom Ritter
sumber
Nice :) Tapi tidak ada backward "for" -loop diuji ... Tapi untuk loop yang disebutkan oleh peirix atau searlea harus hampir sama dengan "while" loop dengan "i--" sebagai kondisinya. Dan itu adalah loop tercepat yang diuji.
SvenFinke
11
Menarik, tapi saya ingin tahu apakah pra-pengurangan akan lebih cepat. Karena tidak perlu menyimpan nilai menengah i.
tvanfosson
Jika saya ingat dengan benar, kata profesinal perangkat keras saya, tes untuk 0 atau tidak 0 adalah "perhitungan" tercepat. Sementara (i--) tes selalu menjadi tes untuk 0. Mungkin itu sebabnya ini tercepat?
StampedeXV
3
@vanfosson jika Anda melakukan pra-pengurangan --imaka Anda harus menggunakan var current = arr[i-1];di dalam loop atau akan dimatikan oleh satu ...
DaveAlger
2
Saya pernah mendengar bahwa saya-- bisa lebih cepat dari --i karena dalam kasus kedua prosesor perlu dikurangi dan kemudian diuji terhadap nilai baru (ada ketergantungan data antara instruksi), sedangkan dalam kasus pertama prosesor dapat uji nilai yang ada dan kurangi nilainya beberapa waktu kemudian. Saya tidak yakin apakah ini berlaku untuk JavaScript atau hanya kode C tingkat sangat rendah.
marcus
128

Saya mencoba memberikan gambaran luas dengan jawaban ini.

Pikiran berikut dalam kurung adalah keyakinan saya sampai saya baru saja menguji masalah ini:

[[Dalam hal bahasa tingkat rendah seperti C / C ++ , kode dikompilasi sehingga prosesor memiliki perintah lompat kondisional khusus ketika sebuah variabel nol (atau tidak nol).
Juga, jika Anda peduli tentang banyak optimasi ini, Anda bisa pergi ++ibukan i++karena ++imerupakan perintah prosesor tunggal sedangkan i++sarana j=i+1, i=j.]]

Loop sangat cepat dapat dilakukan dengan membuka gulungannya:

for(i=800000;i>0;--i)
    do_it(i);

Ini bisa jadi lebih lambat dari pada

for(i=800000;i>0;i-=8)
{
    do_it(i); do_it(i-1); do_it(i-2); ... do_it(i-7);
}

tetapi alasan untuk ini bisa sangat rumit (hanya untuk menyebutkan, ada masalah preprocessing perintah prosesor dan penanganan cache dalam game).

Dalam hal bahasa tingkat tinggi , seperti JavaScript saat Anda bertanya, Anda dapat mengoptimalkan berbagai hal jika Anda mengandalkan perpustakaan, fungsi bawaan untuk perulangan. Biarkan mereka memutuskan cara terbaik untuk melakukannya.

Akibatnya, dalam JavaScript, saya akan menyarankan menggunakan sesuatu seperti

array.forEach(function(i) {
    do_it(i);
});

Ini juga lebih rentan kesalahan dan browser memiliki kesempatan untuk mengoptimalkan kode Anda.

[KETINGGALAN: tidak hanya browser, tetapi Anda juga memiliki ruang untuk mengoptimalkan dengan mudah, cukup mendefinisikan kembali forEachfungsi (tergantung browser) sehingga menggunakan tipuan terbaik terbaru! :) @AMK mengatakan dalam kasus khusus layak menggunakan array.popatau array.shift. Jika Anda melakukannya, letakkan di balik tirai. The maksimal berlebihan adalah dengan menambahkan pilihan untuk forEachmemilih algoritma perulangan.]

Selain itu, juga untuk bahasa tingkat rendah, praktik terbaik adalah menggunakan beberapa fungsi pustaka pintar untuk operasi yang rumit dan berulang jika memungkinkan.

Pustaka-pustaka itu juga dapat meletakkan hal-hal (multi-threaded) di belakang Anda dan juga pemrogram khusus membuat mereka tetap terbarui.

Saya melakukan sedikit pemeriksaan lebih lanjut dan ternyata di C / C ++, bahkan untuk operasi 5e9 = (50,000x100,000), tidak ada perbedaan antara naik dan turun jika pengujian dilakukan terhadap konstanta seperti kata @alestanis. (Hasil JsPerf kadang-kadang tidak konsisten tetapi pada umumnya mengatakan hal yang sama: Anda tidak dapat membuat perbedaan besar.)
Jadi --ikebetulan itu menjadi hal yang "mewah". Itu hanya membuat Anda terlihat seperti programmer yang lebih baik. :)

Di sisi lain, untuk membuka gulungan dalam situasi 5e9 ini, itu membuat saya turun dari 12 detik menjadi 2,5 detik ketika saya naik 10 detik, dan 2,1 detik ketika saya pergi 20 tahun. Itu tanpa optimasi, dan optimasi telah membawa segalanya ke waktu yang tidak terukur. :) (Membuka gulungan dapat dilakukan dengan cara saya di atas atau menggunakan i++, tetapi itu tidak membawa hal-hal di depan dalam JavaScript.)

Semua dalam semua: pertahankan i--/ i++dan ++i/ i++perbaiki wawancara pekerjaan, tetap pada array.forEachatau fungsi perpustakaan kompleks lainnya jika tersedia. ;)

Barney
sumber
18
Kata kuncinya adalah "bisa". Loop yang belum dibuka mungkin juga lebih lambat dari yang asli. Saat mengoptimalkan, selalu ukur agar Anda tahu persis apa dampak perubahan Anda.
Jalf
1
@jalf memang benar, +1. Panjang lloh unlooping yang berbeda (> = 1) berbeda dalam efisiensi. Itulah sebabnya mengapa lebih mudah untuk meninggalkan pekerjaan ini ke perpustakaan jika memungkinkan, belum lagi bahwa browser berjalan pada arsitektur yang berbeda sehingga mungkin lebih baik jika mereka memutuskan bagaimana melakukannya array.each(...). Saya tidak berpikir mereka akan mencoba dan bereksperimen dengan loop forloop polos.
Barney
1
@BarnabasSzabolcs Pertanyaannya adalah untuk JavaScript khusus, bukan bahasa C atau lainnya. Dalam JS ada adalah perbedaan, silakan lihat jawaban saya di bawah. Meskipun tidak berlaku untuk pertanyaan, +1 jawaban yang bagus!
AMK
1
Dan begitulah - +1untuk mendapatkan Anda Great AnswerLencana. Jawaban yang sangat bagus. :)
Rohit Jain
1
APL / A ++ juga bukan bahasa. Orang-orang menggunakan ini untuk menyatakan bahwa mereka tidak tertarik pada spesifik bahasa, tetapi sesuatu yang dibagikan oleh bahasa-bahasa tersebut.
Barney
33

i-- secepat i++

Kode di bawah ini secepat milik Anda, tetapi menggunakan variabel tambahan:

var up = Things.length;
for (var i = 0; i < up; i++) {
    Things[i]
};

Rekomendasi adalah untuk TIDAK mengevaluasi ukuran array setiap kali. Untuk array besar kita dapat melihat penurunan kinerja.

sainiuc
sumber
6
Anda jelas salah di sini. Sekarang kontrol loop memerlukan variabel internal tambahan (i dan lebih tinggi) dan tergantung pada mesin JavaScript ini dapat membatasi potensi untuk mengoptimalkan kode. JIT akan menerjemahkan loop sederhana untuk mengarahkan mesin opcode, tetapi jika loop memiliki terlalu banyak variabel maka JIT tidak akan dapat mengoptimalkan sebaik ini. Secara umum, ini dibatasi oleh arsitektur atau register cpu yang digunakan JIT. Menginisialisasi sekali dan turun hanya solusi terbersih dan karena itu direkomendasikan di semua tempat.
Pavel P
Variabel tambahan akan dihilangkan oleh optimizer dari interpreter / compiler umum. Intinya adalah 'bandingkan dengan 0' - lihat jawaban saya untuk penjelasan lebih lanjut.
H.-Dirk Schmitt
1
Lebih baik menempatkan 'di dalam' loop:for (var i=0, up=Things.length; i<up; i++) {}
thdoan
22

Karena, Anda tertarik pada subjek, lihat posting weblog Greg Reimer tentang tolok ukur loop JavaScript, Apa Cara Tercepat untuk Kode Loop dalam JavaScript? :

Saya membangun rangkaian tes pembandingan loop untuk berbagai cara pengkodean loop dalam JavaScript. Sudah ada beberapa di luar sana, tetapi saya tidak menemukan yang mengakui perbedaan antara array asli dan koleksi HTML.

Anda juga dapat melakukan tes kinerja pada loop dengan membuka https://blogs.oracle.com/greimer/resource/loop-test.html(tidak berfungsi jika JavaScript diblokir di browser oleh, misalnya, NoScript ).

EDIT:

Patokan yang lebih baru yang dibuat oleh Milan Adamovsky dapat dilakukan secara run-time di sini untuk berbagai browser.

Untuk Pengujian di Firefox 17.0 pada Mac OS X 10.6 saya mendapat loop berikut:

var i, result = 0;
for (i = steps - 1; i; i--) {
  result += i;
}

sebagai yang tercepat didahului oleh:

var result = 0;
for (var i = steps - 1; i >= 0; i--) {
  result += i;
}

Contoh benchmark.

dreamcrash
sumber
5
Pos itu sudah berusia 4 tahun sekarang. Mengingat kecepatan (ha!) Di mana mesin JavaScript telah diperbarui, sebagian besar saran cenderung usang - artikel itu bahkan tidak menyebutkan Chrome dan itu mesin V8 JavaScript yang mengkilap.
Yi Jiang
Yap, saya ketinggalan detail itu, terima kasih sudah menunjukkannya. Acara pada waktu itu tidak ada banyak perbedaan antara --i atau i ++ pada loop untuk.
dreamcrash
19

Ini bukan --atau ++, itu adalah operasi perbandingan. Dengan --Anda dapat menggunakan membandingkan dengan 0, sedangkan dengan ++Anda harus membandingkannya dengan panjang. Pada prosesor, bandingkan dengan nol biasanya tersedia, sementara membandingkan dengan bilangan bulat terbatas membutuhkan pengurangan.

a++ < length

sebenarnya dikompilasi sebagai

a++
test (a-length)

Jadi butuh waktu lebih lama pada prosesor saat dikompilasi.

Dr BDO Adams
sumber
15

Jawaban singkat

Untuk kode normal, terutama dalam bahasa tingkat tinggi seperti JavaScript , tidak ada perbedaan kinerja dalam i++dan i--.

Kriteria kinerja adalah penggunaan dalam forloop dan pernyataan pembanding .

Ini berlaku untuk semua bahasa tingkat tinggi dan sebagian besar independen dari penggunaan JavaScript. Penjelasannya adalah kode assembler yang dihasilkan di garis bawah.

Penjelasan detail

Perbedaan kinerja dapat terjadi dalam satu lingkaran. Latar belakangnya adalah bahwa pada tingkat kode assembler Anda dapat melihat bahwa compare with 0hanya satu pernyataan yang tidak memerlukan register tambahan.

Perbandingan ini dikeluarkan pada setiap lintasan loop dan dapat menghasilkan peningkatan kinerja yang terukur.

for(var i = array.length; i--; )

akan dievaluasi ke kode semu seperti ini:

 i=array.length
 :LOOP_START
 decrement i
 if [ i = 0 ] goto :LOOP_END
 ... BODY_CODE
 :LOOP_END

Perhatikan bahwa 0 adalah literal, atau dengan kata lain, nilai konstan.

for(var i = 0 ; i < array.length; i++ )

akan dievaluasi menjadi kode pseudo seperti ini (yang diharapkan dari optimalisasi juru bahasa):

 end=array.length
 i=0
 :LOOP_START
 if [ i < end ] goto :LOOP_END
 increment i
 ... BODY_CODE
 :LOOP_END

Perhatikan bahwa end adalah variabel yang membutuhkan register CPU . Ini dapat meminta register tambahan yang bertukar kode dan membutuhkan pernyataan perbandingan yang lebih mahal dalam ifpernyataan tersebut.

Hanya 5 sen saya

Untuk bahasa tingkat tinggi, keterbacaan, yang memfasilitasi pemeliharaan, lebih penting sebagai peningkatan kinerja kecil.

Biasanya iterasi klasik dari awal hingga akhir lebih baik.

Iterasi yang lebih cepat dari ujung array untuk memulai hasil dalam urutan terbalik yang mungkin tidak diinginkan.

Posting scriptum

Seperti yang ditanyakan dalam komentar: Perbedaan --idan i--dalam evaluasi isebelum atau sesudah pengurangan.

Penjelasan terbaik adalah untuk mencobanya ;-) Ini adalah contoh Bash .

 % i=10; echo "$((--i)) --> $i"
 9 --> 9
 % i=10; echo "$((i--)) --> $i"
 10 --> 9
H.-Dirk Schmitt
sumber
1
1+ Penjelasan yang bagus. Hanya pertanyaan sedikit di luar ruang lingkup, bisakah Anda menjelaskan perbedaan antara --idan i--juga?
Afshin Mehrabani
14

Saya telah melihat rekomendasi yang sama di Sublime Text 2.

Seperti yang sudah dikatakan, peningkatan utama tidak mengevaluasi panjang array pada setiap iterasi dalam for loop. Ini adalah teknik optimasi yang terkenal dan sangat efisien dalam JavaScript ketika array adalah bagian dari dokumen HTML (melakukan foruntuk semua lielemen).

Sebagai contoh,

for (var i = 0; i < document.getElementsByTagName('li').length; i++)

jauh lebih lambat daripada

for (var i = 0, len = document.getElementsByTagName('li').length; i < len; i++)

Dari tempat saya berdiri, peningkatan utama dalam formulir dalam pertanyaan Anda adalah fakta bahwa itu tidak mendeklarasikan variabel tambahan ( lendalam contoh saya)

Tetapi jika Anda bertanya kepada saya, intinya bukan tentang optimasi i++vs i--, tetapi tentang tidak harus mengevaluasi panjang array pada setiap iterasi (Anda dapat melihat tes benchmark pada jsperf ).

BBog
sumber
1
Saya harus mengambil pengecualian untuk kata menghitung di sini. Lihat komentar saya pada jawaban Pavel . Spesifikasi ECMA menyatakan bahwa panjang array tidak dihitung ketika Anda merujuknya.
kojiro
Akankah 'mengevaluasi' menjadi pilihan yang lebih baik? Fakta menarik btw, saya tidak tahu itu
BBog
Variabel tambahan akan dihilangkan oleh optimizer dari interpreter / compiler umum. Hal yang sama berlaku untuk evaluasi array.length. Intinya adalah 'bandingkan dengan 0' - lihat jawaban saya untuk penjelasan lebih lanjut.
H.-Dirk Schmitt
@ H.-DirkSchmitt jawaban masuk akal Anda, sejak lama dalam sejarah JavaScript kompiler tidak mengoptimalkan biaya kinerja rantai pencarian. AFAIK V8 adalah yang pertama mencoba.
kojiro
@ H.-DirkSchmitt seperti yang dikatakan kojiro, ini adalah trik yang terkenal dan mapan. Bahkan jika itu tidak lagi relevan di browser modern, itu masih tidak membuatnya usang. Selain itu, melakukannya dengan memperkenalkan variabel baru untuk panjang atau dengan trik dalam pertanyaan OP, itu masih cara terbaik, imo. Ini hanya hal yang cerdas untuk dilakukan dan praktik yang baik, saya tidak berpikir itu ada hubungannya dengan fakta bahwa kompiler dioptimalkan untuk mengurus sesuatu yang sering dilakukan dengan cara yang buruk di JS
BBog
13

Saya tidak berpikir masuk akal untuk mengatakan bahwa i--itu lebih cepat dari i++pada JavaScript.

Pertama-tama , itu sepenuhnya tergantung pada implementasi mesin JavaScript.

Kedua , asalkan konstruk JIT'ed yang paling sederhana dan diterjemahkan menjadi instruksi asli, lalu i++vsi-- akan sepenuhnya bergantung pada CPU yang mengeksekusinya. Artinya, pada ARM (ponsel) lebih cepat turun ke 0 sejak penurunan dan dibandingkan dengan nol dieksekusi dalam satu instruksi.

Mungkin, Anda berpikir bahwa yang satu lebih buas daripada yang lain karena cara yang disarankan adalah

for(var i = array.length; i--; )

tetapi cara yang disarankan bukan karena yang satu lebih cepat dari yang lain, tetapi hanya karena jika Anda menulis

for(var i = 0; i < array.length; i++)

maka pada setiap iterasi array.lengthharus dievaluasi (mesin JavaScript yang lebih cerdas mungkin bisa mengetahui bahwa loop tidak akan mengubah panjang array). Meskipun terlihat seperti pernyataan sederhana, sebenarnya beberapa fungsi yang dipanggil di bawah kap oleh mesin JavaScript.

Alasan lain, mengapa i--bisa dianggap "lebih cepat" adalah karena mesin JavaScript perlu mengalokasikan hanya satu variabel internal untuk mengontrol loop (variabel ke var i). Jika Anda dibandingkan dengan array.length atau beberapa variabel lain, maka harus ada lebih dari satu variabel internal untuk mengontrol loop, dan jumlah variabel internal adalah aset terbatas mesin JavaScript. Semakin sedikit variabel yang digunakan dalam satu lingkaran semakin banyak peluang JIT untuk optimasi. Itu sebabnya i--bisa dianggap lebih cepat ...

Pavel P
sumber
3
Mungkin perlu diperhatikan ungkapan hati-hati tentang bagaimana array.lengthdievaluasi. Panjangnya tidak dihitung saat Anda merujuknya. (Ini hanya properti yang disetel setiap kali indeks array dibuat atau diubah ). Ketika ada biaya tambahan, itu karena mesin JS belum mengoptimalkan rantai pencarian untuk nama itu.
kojiro
Yah, tidak yakin apa yang dikatakan Ecma spec, tetapi mengetahui tentang beberapa internal dari mesin JavaScript yang berbeda itu tidak mudah getLength(){return m_length; }karena ada beberapa housekeeping yang terlibat. Tetapi jika Anda mencoba untuk berpikir mundur: itu akan cukup cerdik untuk menulis implementasi array di mana panjang harus benar-benar dihitung :)
Pavel P
spesifikasi ECMA mensyaratkan bahwa properti panjang sudah dihitung. The lengthharus diperbarui segera setiap kali properti-yang-adalah-sebuah-array-index ditambahkan atau diubah.
kojiro
Yang ingin saya katakan adalah cukup sulit untuk melanggar spec jika Anda mencoba memikirkannya.
Pavel P
1
x86 seperti ARM dalam hal itu. dec/jnzvs. inc eax / cmp eax, edx / jne.
Peter Cordes
13

Karena tidak ada jawaban lain yang tampaknya menjawab pertanyaan spesifik Anda (lebih dari setengahnya menunjukkan contoh C dan membahas bahasa tingkat rendah, pertanyaan Anda adalah JavaScript). Saya memutuskan untuk menulis sendiri.

Jadi, ini dia:

Jawaban sederhana: i-- umumnya lebih cepat karena tidak harus menjalankan perbandingan dengan 0 setiap kali berjalan, hasil pengujian pada berbagai metode di bawah ini:

Hasil tes: Seperti "dibuktikan" oleh jsPerf ini , arr.pop()sebenarnya adalah loop tercepat sejauh ini. Tapi, berfokus pada --i, i--, i++dan++i seperti yang Anda minta dalam pertanyaan Anda, di sini adalah jsPerf (mereka dari beberapa jsPerf, silakan lihat sumber di bawah ini) hasil diringkas:

--idan i--sama di Firefox sementara i--lebih cepat di Chrome.

Di Chrome, dasar untuk loop ( for (var i = 0; i < arr.length; i++)) lebih cepat dari i--dan--i sementara di Firefox lebih lambat.

Di Chrome dan Firefox keduanya di-cache arr.length lebih cepat secara signifikan dengan Chrome unggul sekitar 170.000 ops / detik.

Tanpa perbedaan yang signifikan, ++ilebih cepat darii++ pada kebanyakan browser, AFAIK, tidak pernah sebaliknya di browser apa pun.

Ringkasan yang lebih pendek: arr.pop() adalah putaran tercepat sejauh ini; untuk loop yang disebutkan secara khusus,i-- adalah loop tercepat.

Sumber: http://jsperf.com/fastest-array-loops-in-javascript/15 , http://jsperf.com/ipp-vs-ppi-2

Saya harap ini menjawab pertanyaan Anda.

AMK
sumber
1
Tampaknya poptes Anda tampaknya cukup cepat karena mengurangi ukuran array menjadi 0 untuk sebagian besar loop - sejauh yang saya tahu. Namun untuk memastikan semuanya adil, saya telah merancang jsperf ini untuk membuat array dengan cara yang sama dengan setiap tes - yang tampaknya menunjukkan .shift()sebagai pemenang untuk beberapa browser saya - bukan apa yang saya harapkan :) jsperf.com / bandingkan-berbagai-jenis-perulangan
Pebbl
Terpilih karena menjadi satu-satunya yang menyebutkan ++i: D
jaggedsoft
12

Itu tergantung pada penempatan array Anda di memori dan rasio hit halaman memori saat Anda mengakses array itu.

Dalam beberapa kasus mengakses anggota array dalam urutan kolom lebih cepat daripada urutan baris karena peningkatan rasio hit.

Akbar Bayati
sumber
1
Jika saja OP bertanya mengapa melintasi matriks yang sama dalam pesanan berbeda dapat mengambil jumlah waktu yang berbeda ..
dcow
1
Menimbang bahwa dalam Sistem Operasi bahwa manajemen memori mereka didasarkan pada Paging, ketika suatu proses membutuhkan data yang tidak ada dalam halaman cache, terjadi kesalahan halaman di OS dan itu harus membawa halaman target ke cache CPU dan ganti dengan halaman lain, oleh karena itu, menyebabkan overhead dalam pemrosesan yang membutuhkan waktu lebih lama daripada saat halaman target dalam cache CPU. Misalkan kita mendefinisikan array besar yang setiap baris di dalamnya lebih besar dari ukuran halaman OS dan kita mengaksesnya dalam urutan baris, dalam hal ini rasio kesalahan halaman meningkat dan hasilnya lebih lambat daripada akses urutan kolom ke array itu.
Akbar Bayati
Kesalahan halaman tidak sama dengan kesalahan cache. Anda hanya kesalahan halaman jika memori Anda paged keluar ke disk. Mengakses array multidimensi secara berurutan tentang bagaimana mereka disimpan dalam memori lebih cepat karena lokalitas cache (menggunakan semua byte dari garis cache saat diambil), bukan karena kesalahan halaman. (kecuali perangkat kerja Anda terlalu besar untuk komputer yang Anda gunakan.)
Peter Cordes
10

Terakhir kali saya peduli tentang itu ketika menulis 6502 perakitan (8-bit, yeah!). Keuntungan besar adalah bahwa sebagian besar operasi aritmatika (terutama pengurangan) memperbarui satu set bendera, salah satunya adalah Z, indikator 'mencapai nol'.

Jadi, pada akhir loop Anda baru saja melakukan dua instruksi: DEC(decrement) dan JNZ(melompat jika tidak nol), tidak diperlukan perbandingan!

Javier
sumber
Dalam kasus JavaScript jelas itu tidak berlaku (karena ini berjalan pada CPU yang tidak memiliki op-kode seperti itu). Kemungkinan besar alasan sebenarnya di balik i--vs i++adalah bahwa dengan yang sebelumnya Anda tidak memperkenalkan variabel kontrol tambahan dalam lingkup loop. Lihat jawaban saya di bawah ini ...
Pavel P
1
benar, itu benar-benar tidak berlaku; tapi itu gaya C yang sangat umum, dan memang terlihat lebih bersih bagi kita yang terbiasa dengan itu. :-)
Javier
x86 dan ARM sama-sama seperti 6502 dalam hal ini. dec/jnzalih-alih inc/cmp/jneuntuk kasus x86. Anda tidak akan melihat loop kosong berjalan lebih cepat (keduanya akan menjenuhkan throughput cabang), tetapi menghitung mundur sedikit mengurangi overhead loop. Prefetcher Intel HW saat ini juga tidak terganggu oleh pola akses memori yang berjalan dalam urutan menurun. CPU yang lebih lama Saya pikir bisa melacak seperti 4 stream mundur dan 6 atau 10 stream maju, IIRC.
Peter Cordes
7

Ini dapat dijelaskan oleh JavaScript (dan semua bahasa) yang pada akhirnya diubah menjadi opcode untuk dijalankan pada CPU. CPU selalu memiliki instruksi tunggal untuk membandingkan dengan nol, yang sangat cepat.

Sebagai tambahan, jika Anda dapat menjamin countselalu >= 0, Anda dapat menyederhanakan untuk:

for (var i = count; i--;)
{
  // whatever
}
searlea
sumber
1
Kode sumber yang lebih pendek tidak selalu berarti akan lebih cepat. Sudahkah Anda mengukurnya?
Greg Hewgill
Ups, saya melewatkan yang ini. Kuku di kepala ada chap.
Robert
1
Saya ingin melihat sumber rakitan tempat membandingkan dengan 0 berbeda. Sudah beberapa tahun, tetapi pada suatu waktu saya melakukan satu ton perakitan kode dan saya tidak bisa seumur hidup saya memikirkan cara untuk melakukan perbandingan / uji terhadap 0 dengan cara yang tidak bisa sama cepatnya untuk bilangan bulat lainnya. Namun, apa yang Anda katakan tidak benar. Frustrasi karena saya tidak tahu mengapa!
Brian Knoblauch
7
@Brian Knoblauch: Jika Anda menggunakan instruksi seperti "dec eax" (kode x86) maka instruksi itu secara otomatis menetapkan tanda Z (nol) yang dapat segera Anda uji tanpa harus menggunakan instruksi pembanding lain di antaranya.
Greg Hewgill
1
Ketika menafsirkan Javascript, saya ragu bahwa opcodes akan menjadi hambatan. Lebih mungkin bahwa token yang lebih sedikit berarti penerjemah dapat memproses kode sumber lebih cepat.
Todd Owen,
6

Ini tidak tergantung pada tanda --atau ++, tetapi tergantung pada kondisi yang Anda terapkan dalam loop.

Sebagai contoh: Loop Anda lebih cepat jika variabel memiliki nilai statis daripada jika loop Anda memeriksa kondisi setiap saat, seperti panjang array atau kondisi lainnya.

Tetapi jangan khawatir tentang pengoptimalan ini, karena kali ini pengaruhnya diukur dalam nanodetik.

Arvind Kanjariya
sumber
beberapa nanosecond loop dapat menjadi detik ... itu bukan ide yang buruk untuk mengoptimalkan ketika Anda punya waktu untuk itu
Buksy
6

for(var i = array.length; i--; )tidak jauh lebih cepat. Tetapi ketika Anda menggantinya array.lengthdengan super_puper_function(), itu mungkin jauh lebih cepat (karena itu disebut di setiap iterasi). Itulah bedanya.

Jika Anda akan mengubahnya pada 2014, Anda tidak perlu memikirkan pengoptimalan. Jika Anda akan mengubahnya dengan "Cari & Ganti", Anda tidak perlu memikirkan pengoptimalan. Jika Anda tidak punya waktu, Anda tidak perlu memikirkan pengoptimalan. Tapi sekarang, Anda punya waktu untuk memikirkannya.

PS: i--tidak lebih cepat dari i++.

Dmitry Isaev
sumber
6

Singkatnya: Sama sekali tidak ada perbedaan dalam melakukan ini dalam JavaScript.

Pertama-tama, Anda dapat mengujinya sendiri:

Anda tidak hanya dapat menguji dan menjalankan skrip apa pun di pustaka JavaScript apa pun, tetapi Anda juga memiliki akses ke sejumlah skrip yang ditulis sebelumnya, serta kemampuan untuk melihat perbedaan antara waktu eksekusi di berbagai browser pada platform yang berbeda.

Jadi sejauh yang Anda bisa lihat, tidak ada perbedaan antara kinerja di lingkungan apa pun.

Jika Anda ingin meningkatkan kinerja skrip Anda, hal-hal yang dapat Anda coba lakukan:

  1. Miliki var a = array.length;pernyataan sehingga Anda tidak akan menghitung nilainya setiap kali dalam loop
  2. Lakukan loop membuka gulungan http://en.wikipedia.org/wiki/Loop_unwinding

Tetapi Anda harus memahami bahwa peningkatan yang dapat Anda peroleh akan sangat kecil, sehingga sebagian besar Anda bahkan tidak perlu mempedulikannya.

Pendapat saya sendiri mengapa kesalahpahaman seperti itu (Dec vs Inc) muncul

Dahulu kala ada instruksi mesin yang umum, DSZ (Decrement and Skip on Zero). Orang-orang yang diprogram dalam bahasa assembly menggunakan instruksi ini untuk mengimplementasikan loop untuk menyimpan register. Sekarang fakta kuno ini sudah usang, dan saya cukup yakin Anda tidak akan mendapatkan peningkatan kinerja dalam bahasa apa pun menggunakan perbaikan semu ini.

Saya pikir satu-satunya cara pengetahuan tersebut dapat berkembang di zaman kita adalah ketika Anda membaca kode orang lain. Lihat konstruksi seperti itu dan tanyakan mengapa itu diterapkan dan di sini jawabannya: "itu meningkatkan kinerja karena dibandingkan dengan nol". Anda menjadi bingung dengan pengetahuan yang lebih tinggi dari kolega Anda dan berpikir untuk menggunakannya agar lebih pintar :-)

Salvador Dali
sumber
Menarik, tetapi untuk pengujian Anda yang berjalan di bawah firefox 16.0.2 pada win7, loop penurunan adalah 29% lebih lambat ... EDIT: Abaikan itu. Pengujian berulang terbukti tidak meyakinkan, ada sejumlah kebisingan yang mengejutkan dalam hasil pengujian saya untuk pengujian selanjutnya. Tidak yakin kenapa.
Ya saya mencoba menjelaskannya dengan menutup yang lainnya dan hanya menjalankan tes. Masih mendapat hasil miring. Sangat aneh.
Saya pikir Anda melewatkan poin sebenarnya mengapa menjadi nol dianggap lebih baik dalam JavaScript. Ini terutama karena cara ini hanya satu variabel yang mengontrol eksekusi loop, misalnya cara ini optimizer / JITer memiliki lebih banyak ruang untuk perbaikan. Menggunakan array.lengthtidak harus dikenakan penalti kinerja, hanya karena mesin virtual JS cukup pintar untuk mengetahui apakah array tidak dimodifikasi oleh tubuh loop. Lihat jawaban saya di bawah ini.
Pavel P
1
nitpicking: fakta kuno ini (optimisasi bahasa assembly) tidak usang, hanya misterius. seperti pada Anda tidak perlu tahu kecuali Anda benar-benar tahu. :-)
Javier
6

Saya membuat perbandingan di jsbench .

Seperti yang ditunjukkan alestani, satu hal yang membutuhkan waktu dalam loop menanjak, adalah mengevaluasi, untuk setiap iterasi, ukuran array Anda. Dalam lingkaran ini:

for ( var i = 1; i <= array.length; i++ )

Anda mengevaluasi .lengthsetiap kali Anda menambah i. Yang ini:

for ( var i = 1, l = array.length; i <= l; i++ )

Anda mengevaluasi .lengthhanya sekali, ketika Anda menyatakan i. Yang ini:

for ( var i = array.length; i--; )

perbandingannya implisit, itu terjadi sebelum decrementing i, dan kode ini sangat mudah dibaca. Namun, apa yang dapat membuat perbedaan luar biasa, adalah apa yang Anda masukkan ke dalam loop.

Loop dengan fungsi panggilan ke (didefinisikan di tempat lain):

for (i = values.length; i-- ;) {
  add( values[i] );
}

Ulangi dengan kode sebaris:

var sum = 0;
for ( i = values.length; i-- ;) {
  sum += values[i];
}

Jika Anda dapat memasukkan kode Anda, alih-alih memanggil fungsi, tanpa mengorbankan keterbacaan, Anda dapat membuat lingkaran dengan urutan lebih cepat!


Catatan : karena peramban menjadi bagus dalam inlining fungsi sederhana, itu sangat tergantung pada seberapa kompleks kode Anda. Jadi, profil sebelum dioptimalkan, karena

  1. Kemacetan mungkin terjadi di tempat lain (ajax, reflow, ...)
  2. Anda dapat memilih algoritma yang lebih baik
  3. Anda dapat memilih struktur data yang lebih baik

Tapi ingat:

Kode ditulis untuk dibaca orang, dan hanya dilakukan secara kebetulan oleh mesin.

Spyryto
sumber
+1 untuk jawaban ini dan untuk tolok ukur. Saya telah menambahkan tes forEach dan mengerjakan ulang patokan ke file mandiri runnable di browser serta di Node. jsfiddle.net/hta69may/2 . Untuk Node "Reverse loop, perbandingan implisit, kode inlined" adalah yang tercepat. Tetapi pengujian dalam FF 50 menunjukkan hasil yang aneh: tidak hanya timing hampir 10 kali lebih sedikit (!) Tetapi kedua tes "forEach" sama cepatnya dengan "loop terbalik". Mungkin Node guys harus menggunakan mesin JS Mozilla, bukan V8? :)
Fr0sT
4

Cara Anda melakukannya sekarang tidak lebih cepat (selain dari itu menjadi loop tidak terbatas, saya kira Anda harus melakukannya i--.

Jika Anda ingin membuatnya lebih cepat, lakukan:

for (i = 10; i--;) {
    //super fast loop
}

tentu saja Anda tidak akan melihatnya dalam lingkaran kecil. Alasannya lebih cepat adalah karena Anda mengurangi i sambil memeriksa bahwa itu "benar" (itu dinilai menjadi "salah" ketika mencapai 0)

peirix
sumber
1
Apakah Anda kehilangan titik koma? (i = 10; i--;)
searlea
Ya ya, saya memperbaiki kesalahannya. Dan jika kita akan pilih-pilih saya akan menunjukkan Anda lupa titik koma setelah Anda -! Heh.
djdd87
Mengapa itu lebih cepat? Sumber yang lebih pendek tidak berarti akan lebih cepat. Sudahkah Anda mengukurnya?
Greg Hewgill
4
Ya, saya telah mengukurnya, dan saya tidak mengatakan sumber yang lebih pendek membuatnya lebih cepat, tetapi lebih sedikit operasi membuatnya lebih cepat.
peirix
4

Terkadang membuat beberapa perubahan kecil pada cara kita menulis kode kita dapat membuat perbedaan besar pada seberapa cepat kode kita benar-benar berjalan. Satu area di mana perubahan kode kecil dapat membuat perbedaan besar untuk waktu eksekusi adalah di mana kita memiliki for loop yang memproses array. Di mana array adalah elemen pada halaman web (seperti tombol radio) perubahan memiliki efek terbesar tetapi masih layak menerapkan perubahan ini bahkan ketika array internal ke kode Javascript.

Cara konvensional mengkode loop for untuk memproses lis array seperti ini:

for (var i = 0; i < myArray.length; i++) {...

Masalah dengan ini adalah bahwa mengevaluasi panjang array menggunakan myArray.length membutuhkan waktu dan cara kita mengkodekan loop berarti evaluasi ini harus dilakukan setiap kali di sekitar loop. Jika array berisi 1000 elemen maka panjang array akan dievaluasi 1001 kali. Jika kita melihat tombol radio dan memiliki myForm.myButtons.length maka akan butuh waktu lebih lama untuk mengevaluasi karena kelompok tombol yang sesuai dalam formulir yang ditentukan harus terlebih dahulu ditemukan sebelum panjangnya dapat dievaluasi setiap kali di sekitar loop.

Jelas kami tidak berharap panjang array berubah saat kami memprosesnya sehingga semua perhitungan ulang panjang ini hanya menambah waktu pemrosesan yang tidak perlu. (Tentu saja jika Anda memiliki kode di dalam loop yang menambah atau menghapus entri array maka ukuran array dapat berubah di antara iterasi dan jadi kami tidak dapat mengubah kode yang mengujinya)

Apa yang bisa kita lakukan untuk memperbaiki ini untuk loop di mana ukurannya tetap adalah untuk mengevaluasi panjangnya sekali pada awal loop dan menyimpannya dalam variabel. Kami kemudian dapat menguji variabel untuk memutuskan kapan harus mengakhiri loop. Ini jauh lebih cepat daripada mengevaluasi panjang array setiap kali terutama ketika array berisi lebih dari beberapa entri atau merupakan bagian dari halaman web.

Kode untuk melakukan ini adalah:

for (var i = 0, var j = myArray.length; i < j; i++) {...

Jadi sekarang kita hanya mengevaluasi ukuran array sekali dan menguji penghitung loop kita terhadap variabel yang memegang nilai itu setiap kali di sekitar loop. Variabel tambahan ini dapat diakses lebih cepat daripada mengevaluasi ukuran array dan kode kita akan berjalan lebih cepat dari sebelumnya. Kami hanya memiliki satu variabel tambahan dalam skrip kami.

Seringkali tidak masalah apa pun urutan kami memproses array selama semua entri dalam array diproses. Jika demikian, kita dapat membuat kode kita sedikit lebih cepat dengan menghapus variabel tambahan yang baru saja kita tambahkan dan memproses array dalam urutan terbalik.

Kode akhir yang memproses array kami dengan cara yang seefisien mungkin adalah:

for (var i = myArray.length-1; i > -1; i--) {...

Kode ini masih hanya mengevaluasi ukuran array sekali di awal tetapi alih-alih membandingkan penghitung loop dengan variabel kita membandingkannya dengan konstanta. Karena konstanta bahkan lebih efektif untuk diakses daripada variabel dan karena kita memiliki satu pernyataan penugasan yang lebih sedikit daripada sebelum versi ketiga kode kita sekarang sedikit lebih efisien daripada versi kedua dan jauh lebih efisien daripada yang pertama.

Sid
sumber
4

++vs. --tidak masalah karena JavaScript adalah bahasa yang ditafsirkan, bukan bahasa yang dikompilasi. Setiap instruksi diterjemahkan ke lebih dari satu bahasa mesin dan Anda tidak perlu peduli dengan detail darah.

Orang-orang yang berbicara tentang menggunakan --(atau ++) menggunakan instruksi perakitan secara efisien adalah salah. Instruksi ini berlaku untuk bilangan bulat aritmatika dan tidak ada bilangan bulat dalam JavaScript, hanya angka .

Anda harus menulis kode yang dapat dibaca.

Salman A
sumber
3

Dalam banyak kasus, ini pada dasarnya tidak ada hubungannya dengan fakta bahwa prosesor dapat dibandingkan dengan nol lebih cepat daripada perbandingan lainnya.

Ini karena hanya beberapa mesin Javascript (yang ada di daftar JIT) yang benar-benar menghasilkan kode bahasa mesin.

Sebagian besar mesin Javascript membangun representasi internal dari kode sumber yang kemudian mereka tafsirkan (untuk mendapatkan gambaran seperti apa ini, lihat di dekat bagian bawah halaman ini tentang SpiderMonkey Firefox ). Umumnya jika sepotong kode melakukan hal yang sama tetapi mengarah ke representasi internal yang lebih sederhana, itu akan berjalan lebih cepat.

Ingatlah bahwa dengan tugas-tugas sederhana seperti menambah / mengurangi satu dari suatu variabel, atau membandingkan suatu variabel dengan sesuatu, overhead penerjemah bergerak dari satu "instruksi" internal ke yang berikutnya cukup tinggi, sehingga semakin sedikit "instruksi" yang ada. digunakan secara internal oleh mesin JS, semakin baik.

Artelius
sumber
3

Yah, saya tidak tahu tentang JavaScript, itu harus benar-benar hanya masalah panjang array evaluasi ulang dan mungkin ada hubungannya dengan array asosiatif (jika Anda hanya mengurangi, itu tidak mungkin entri baru perlu dialokasikan - jika array padat, yaitu seseorang dapat mengoptimalkan untuk itu).

Dalam perakitan level rendah, ada instruksi looping, yang disebut DJNZ (decrement and jump jika tidak nol). Jadi penurunan dan lompatan adalah semua dalam satu instruksi, membuatnya mungkin jadi sedikit lebih cepat daripada INC dan JL / JB (kenaikan, lompat jika kurang dari / lompat jika di bawah). Juga, membandingkan dengan nol lebih sederhana daripada membandingkan dengan nomor lain. Tapi semua itu benar-benar marjinal dan juga tergantung pada arsitektur target (bisa membuat perbedaan misalnya pada Arm di smartphone).

Saya tidak berharap perbedaan tingkat rendah ini memiliki dampak besar pada bahasa yang ditafsirkan, saya hanya belum melihat DJNZ di antara tanggapan jadi saya pikir saya akan berbagi pemikiran yang menarik.

babi
sumber
Sebagai catatan, DJNZadalah instruksi dalam 8051 (z80) ISA. x86 dec/jnzbukan inc/cmp/jne, dan tampaknya lengan memiliki sesuatu yang serupa. Saya cukup yakin ini bukan penyebab perbedaan Javascript; itu dari memiliki lebih banyak eval dalam kondisi loop.
Peter Cordes
3

Itu digunakan untuk dikatakan bahwa -Saya lebih cepat (dalam C ++) karena hanya ada satu hasil, nilai dikurangi. i-- perlu menyimpan nilai yang dikurangi kembali ke i dan juga mempertahankan nilai asli sebagai hasilnya (j = i--;). Dalam kebanyakan kompiler, ini menggunakan dua register daripada satu yang dapat menyebabkan variabel lain harus dituliskan ke memori daripada disimpan sebagai variabel register.

Saya setuju dengan yang lain yang mengatakan tidak ada bedanya hari ini.

Semut
sumber
3

Dengan kata-kata yang sangat sederhana

"Aku-- dan aku ++. Sebenarnya, mereka berdua membutuhkan waktu yang sama".

tetapi dalam kasus ini ketika Anda memiliki operasi tambahan .. prosesor mengevaluasi .length setiap kali variabel bertambah 1 dan dalam kasus penurunan .. khususnya dalam kasus ini, ia akan mengevaluasi .length hanya sekali sampai kita mendapatkan 0.

Ravi_Parmar
sumber
3

Pertama, i++dan i--luangkan waktu yang sama persis pada bahasa pemrograman apa pun, termasuk JavaScript.

Kode berikut membutuhkan waktu yang jauh berbeda.

Cepat:

for (var i = 0, len = Things.length - 1; i <= len; i++) { Things[i] };

Lambat:

for (var i = 0; i <= Things.length - 1; i++) { Things[i] };

Karena itu kode berikut juga membutuhkan waktu yang berbeda.

Cepat:

for (var i = Things.length - 1; i >= 0; i--) { Things[i] };

Lambat:

for (var i = 0; i <= Things.length - 1; i++) { Things[i] };

PS Slow lambat hanya untuk beberapa bahasa (mesin JavaScript) karena optimasi kompiler. Cara terbaik adalah menggunakan '<' sebagai gantinya '<=' (atau '=') dan '--i' sebagai gantinya 'i--' .

Dmitry
sumber
3

Tidak banyak waktu dikonsumsi oleh i-- atau i ++. Jika Anda masuk jauh ke dalam arsitektur CPU ++lebih cepat daripada --, karena --operasi akan melakukan komplemen 2's, tetapi itu terjadi di dalam perangkat keras sehingga ini akan membuatnya cepat dan tidak ada perbedaan besar antara ++dan --juga operasi ini dianggap sebagai paling tidak waktu yang digunakan dalam CPU.

Untuk loop berjalan seperti ini:

  • Inisialisasi variabel satu kali di awal.
  • Periksa kendala dalam operan kedua loop, <, >, <=, dll
  • Kemudian terapkan loop.
  • Tambahkan loop dan loop lagi untuk melempar proses ini lagi.

Begitu,

for (var i = Things.length - 1; i >= 0; i--) {
    Things[i]
}; 

akan menghitung panjang array hanya sekali di awal dan ini tidak banyak waktu, tetapi

for(var i = array.length; i--; ) 

akan menghitung panjang di setiap loop, sehingga akan menghabiskan banyak waktu.

Omar Freewan
sumber
var i = Things.length - 1; i >= 0; i--akan menghitung panjang 1 kali juga.
Dmitry
1
Saya tidak yakin apa artinya " --operasi akan melakukan komplemen 2", tetapi saya menganggap itu berarti akan meniadakan sesuatu. Tidak, itu tidak meniadakan apa pun pada arsitektur apa pun. Mengurangi 1 sama mudahnya dengan menambahkan 1, Anda hanya membuat sirkuit yang meminjam daripada membawa.
Olathe
1

Pendekatan terbaik untuk menjawab pertanyaan semacam ini adalah dengan benar-benar mencobanya. Atur loop yang menghitung sejuta iterasi atau apa pun, dan lakukan keduanya. Waktu kedua loop, dan bandingkan hasilnya.

Jawabannya mungkin tergantung pada browser yang Anda gunakan. Beberapa akan memiliki hasil yang berbeda dari yang lain.

Greg Hewgill
sumber
4
Itu masih tidak akan menjawab pertanyaannya tentang mengapa lebih cepat. Dia baru saja mendapatkan patokan, tanpa sepengetahuan mengapa itu terjadi ...
peirix
3
Itu benar. Namun, tanpa mengetahui implementasi pasti dari setiap mesin Javascript di setiap browser, hampir tidak mungkin untuk menjawab bagian "mengapa". Banyak jawaban di sini memberikan rekomendasi anekdotal seperti "gunakan predecrement alih-alih postdecrement" (trik pengoptimalan C ++) dan "bandingkan dengan nol" yang mungkin benar dalam bahasa yang dikompilasi kode asli tetapi Javascript cukup jauh dari bare metal dari CPU.
Greg Hewgill
4
-1 Saya sepenuhnya tidak setuju bahwa pendekatan terbaik adalah dengan mencobanya. Beberapa contoh tidak menggantikan pengetahuan kolektif, dan itulah inti dari forum seperti ini.
Christophe
1

Menyukainya, banyak tanda tetapi tidak ada jawaban: D

Sederhananya perbandingan terhadap nol selalu merupakan perbandingan tercepat

Jadi (a == 0) sebenarnya lebih cepat dalam mengembalikan True daripada (a == 5)

Ini kecil dan tidak signifikan dan dengan 100 juta baris dalam koleksi itu bisa diukur.

yaitu pada loop ke atas Anda mungkin mengatakan di mana i <= array.length dan akan bertambah i

pada loop bawah Anda mungkin mengatakan di mana i> = 0 dan akan mengurangi i.

Perbandingannya lebih cepat. Bukan 'arah' loop.

Robert
sumber
Tidak ada jawaban untuk pertanyaan seperti yang disebutkan karena mesin Javascript semuanya berbeda dan jawabannya tergantung pada browser mana Anda mengukurnya.
Greg Hewgill
Tidak, perbandingan yang diterima secara mendasar dengan nol adalah yang tercepat. Meskipun pernyataan Anda benar juga, aturan emas membandingkan dengan nol adalah mutlak.
Robert
4
Itu benar hanya jika kompiler memilih untuk melakukan optimasi itu, yang tentunya tidak dijamin. Compiler mungkin menghasilkan kode yang persis sama untuk (a == 0) dan (a == 5), kecuali untuk nilai konstanta. CPU tidak akan membandingkan dengan 0 lebih cepat daripada terhadap nilai lainnya, jika kedua sisi perbandingan adalah variabel (dari sudut pandang CPU). Umumnya hanya kompiler kode asli yang memiliki kesempatan untuk mengoptimalkan pada level ini.
Greg Hewgill
1

BANTUAN ORANG LAIN MENGHINDARI HEADACHE --- PILIH INI !!!

Jawaban paling populer di halaman ini tidak berfungsi untuk Firefox 14 dan tidak lulus jsLinter. "while" loop membutuhkan operator pembanding, bukan penugasan. Ia bekerja pada chrome, safari, dan bahkan ie. Tapi mati di firefox.

INI RUSAK!

var i = arr.length; //or 10
while(i--)
{
  //...
}

INI AKAN BEKERJA! (bekerja pada firefox, melewati jsLinter)

var i = arr.length; //or 10
while(i>-1)
{
  //...
  i = i - 1;
}
mrbinky3000
sumber
2
Saya baru saja mencobanya di Firefox 14 dan bekerja dengan baik. Saya telah melihat contoh dari perpustakaan produksi yang menggunakan while (i--)dan yang bekerja di banyak browser. Mungkinkah ada sesuatu yang aneh dengan tes Anda? Apakah Anda menggunakan Firefox 14 versi beta?
Matt Browne
1

Ini hanya dugaan, tapi mungkin itu karena prosesor lebih mudah untuk membandingkan sesuatu dengan 0 (i> = 0) daripada dengan nilai lain (i <Things.length).

Rorchackh
sumber
3
+1 Jangan orang lain menolak. Meskipun evaluasi berulang .length jauh lebih merupakan masalah daripada inc / decrement yang sebenarnya, pemeriksaan untuk akhir loop mungkin penting. Kompiler C saya memberikan beberapa peringatan pada loop seperti: "komentar # 1544-D: (ULP 13.1) Loop terdeteksi terdeteksi. Merekomendasikan loop menghitung mundur karena mendeteksi nol lebih mudah"
harper