Loop adalah salah satu mekanisme terpenting dalam semua bahasa pemrograman, dan loop tidak terbuka di hampir semua program komputer dengan signifikansi praktis (penyortiran, permintaan, dll.). Looping juga merupakan bagian yang sangat merepotkan dari optimasi program. Kita sering perlu terus mengoptimalkan kompleksitas program, tetapi kita terjerat dalam pilihan antara kompleksitas waktu dan kompleksitas ruang karena perulangan.
Dalam JavaScript, ada 3 loop asli, untuk () {}, while () {} dan do {} while (), dan yang paling umum digunakan untuk () {}.
Namun, karena adalah loop yang paling mungkin diabaikan oleh insinyur JavaScript saat mengoptimalkan program.
Pertama -tama mari kita tinjau pengetahuan dasar untuk.
Sintaks untuk JavaScript diwarisi dari bahasa C, dan ada dua cara untuk menggunakan sintaks dasar untuk loop.
1. Looping Array
Sintaks dasar untuk loop
Salinan kode adalah sebagai berikut:
untuk ( / * inisialisasi * /2 / * kondisi penilaian * /2 / * pemrosesan loop * /) {
// ... kode logis
}
Kami akan menjelaskan secara rinci dengan sepotong kode instan.
Salinan kode adalah sebagai berikut:
var array = [1, 2, 3, 4, 5];
var sum = 0;
untuk (var i = 0, len = array.length; i <len; ++ i) {
jumlah += array [i];
}
Console.log ('Jumlah item array adalah %d.', Sum);
// => Jumlah item array adalah 15.
Dalam kode ini, pertama -tama kami mendefinisikan dan menginisialisasi array yang menyimpan item yang akan diakumulasikan dan variabel pembentukan jumlah. Selanjutnya, kami memulai loop. Dalam kode inisialisasi ini untuk loop, kami juga mendefinisikan dan menginisialisasi dua variabel: i (counter) dan len (alias panjang array loop). Ketika saya kurang dari Len, kondisi loop ditetapkan dan kode logis dijalankan; Setelah setiap kode logis dieksekusi, saya akan bertambah dengan 1.
Dalam kode logis loop, kami menambahkan ketentuan array dari loop saat ini ke variabel SUM.
Siklus ini diwakili oleh diagram alur sebagai berikut:
Dari bagan aliran ini, tidak sulit untuk menemukan bahwa badan loop nyata dalam program tidak hanya berisi kode logis kami, tetapi juga termasuk penilaian eksekusi dan pemrosesan loop yang mengimplementasikan loop itu sendiri.
Dengan cara ini, ide -ide optimasi kami akan jelas dan kami dapat mengoptimalkan dari empat aspek.
1. Kode inisialisasi sebelum badan loop
2. Kondisi penilaian eksekusi di badan loop
3. Kode logis
4. Pemrosesan kode setelah kode logis
PS: Ada hubungan penting antara poin pertama dan poin kedua.
1.1 Mengoptimalkan Kode Inisialisasi dan Kondisi Penilaian Eksekusi
Pertama -tama mari kita lihat sepotong kode yang sangat akrab dengan semua orang.
Salinan kode adalah sebagai berikut:
// salah!
untuk (var i = 02 i <list.length2 ++ i) {
// ... kode logis
}
Saya percaya bahwa sebagian besar insinyur yang menulis JavaScript masih menggunakan metode loop yang tampaknya normal ini, tetapi mengapa saya mengatakan itu salah di sini?
Mari kita pisahkan semuanya dalam lingkaran ini dan lihatlah:
1. Inisialisasi Kode - Loop ini hanya mendefinisikan dan menginisialisasi variabel penghitung.
2. Kondisi penilaian eksekusi - Memang benar ketika penghitung kurang dari panjang daftar.
3. Kode Pemrosesan - Penghitung bertambah dengan 1.
Mari kita tinjau diagram alur di atas dan cari tahu apakah ada yang salah dengan itu?
Badan loop nyata tidak hanya memiliki kode logis kita, tetapi juga mencakup penilaian eksekusi dan kode pemrosesan yang mengimplementasikan loop itu sendiri. Dengan kata lain, kondisi penilaian I <list.length harus dieksekusi sebelum setiap loop. Dalam JavaScript, diperlukan kueri saat membaca properti atau metode objek.
Anda sepertinya mengerti sesuatu, bukan? Ada dua operasi dalam kondisi penilaian ini: 1. Meminta atribut panjang dari array daftar; 2. Bandingkan ukuran i dan list.length.
Dengan asumsi bahwa array daftar berisi N elemen, program perlu melakukan operasi 2n dalam penilaian pelaksanaan loop ini.
Jika kita mengubah kode ke ini:
Salinan kode adalah sebagai berikut:
// Dengan baik
untuk (var i = 0, len = list.length; i <len; ++ i) {
// ...
}
Dalam kode yang ditingkatkan ini, kami menambahkan definisi dan menginisialisasi variabel LEN untuk menyimpan nilai daftar. Panjang dalam kode inisialisasi sebelum eksekusi badan loop (konten yang relevan tentang variabel, ekspresi, pointer dan nilai akan dibahas dalam artikel kedua). Dengan cara ini, kita tidak perlu menanyakan daftar array lagi dalam penilaian eksekusi di badan loop, dan operan adalah setengah dari yang asli.
Dalam langkah -langkah di atas, kami telah meningkatkan kompleksitas waktu algoritma, dan bagaimana kami harus melakukannya jika kami ingin terus mengoptimalkan kompleksitas ruang? Jika kode logika Anda tidak dibatasi oleh Loop Order, Anda dapat mencoba metode optimasi berikut.
Salinan kode adalah sebagai berikut:
untuk (var i = list.length -1; i> = 0; --i) {
// ...
}
Kode ini loop maju dengan membalikkan urutan loop, dimulai dengan subskrip elemen terakhir (list.length - 1). Untuk mengurangi jumlah variabel yang diperlukan untuk loop menjadi 1, dan dalam penilaian eksekusi, jumlah kueri variabel berkurang dan waktu yang dihabiskan sebelum melaksanakan instruksi CPU berkurang.
1.2 Mengoptimalkan kode logika
Dalam satu loop, kami mendapatkan elemen array saat ini dari loop, secara alami untuk melakukan beberapa operasi di atasnya atau menggunakannya, yang pasti mengarah ke beberapa panggilan ke elemen.
Salinan kode adalah sebagai berikut:
var array = [
{name: 'Will Wen Gunn', ketik: 'hentai'},
{name: 'vill lin', type: 'moegril'}
];
untuk (var i = array.length -1; i> = 0; --i) {
console.log ('name: %s', array [i] .name);
console.log ('dia adalah (n) %s', array [i] .peype);
console.log ('/r/n');
}
/*=>
Nama: Vill Lin
Dia adalah moegril (n)
Nama: Akankah Wen Gunn
Dia adalah hentai (n)
*/
Dalam kode ini, program perlu meminta nama dan mengetik atribut dari setiap elemen array. Jika array memiliki elemen N, program akan melakukan kueri objek 4N.
Salinan kode adalah sebagai berikut:
1. Array [i]
2. Array [i] .Name
3. Array [i]
4. Array [i] .Type
Saya yakin Anda harus memikirkan solusi saat ini, yaitu, menetapkan nilai elemen array saat ini ke suatu variabel, dan kemudian menggunakannya dalam kode logis.
Salinan kode adalah sebagai berikut:
var array = [
{name: 'Will Wen Gunn', ketik: 'hentai'},
{name: 'vill lin', type: 'moegril'}
];
var orang = null;
untuk (var i = array.length -1; i> = 0 && (orang = array [i]); --i) {
console.log ('name: %s', person.name);
console.log ('Dia adalah (n) %s', person.Type);
console.log ('/r/n');
}
orang = null;
Ini terlihat jauh lebih indah.
Salinan kode adalah sebagai berikut:
1. Array [i] => var orang
2. Person.Name
3. orang. Type
Ini agak seperti foreach di emcascript5, tetapi perbedaan antara keduanya sangat besar, jadi saya tidak akan menjelaskannya di sini.
PS: Terima kasih atas koreksi Anda. Setelah percobaan, saya menemukan bahwa jika elemen dalam array ditentukan dengan memberikan nilai secara langsung, nilai yang diperoleh dalam loop harus nilai, bukan pointer. Jadi apakah Anda mendefinisikan ekspresi atau variabel, akan ada permintaan ruang memori tambahan.
1.3 Mengoptimalkan kode pemrosesan
Faktanya, tidak banyak untuk mengoptimalkan kode pemrosesan di badan loop, dan penghitung I cukup untuk meningkatkan 1 dengan sendirinya.
PS: Jika Anda memiliki saran atau metode yang bagus, berikan mereka. :)
2. Objek melingkar (objek)
Dalam JavaScript, untuk juga dapat melintasi sifat dan metode objek. Perlu dicatat bahwa loop untuk tidak dapat melalui jenis pembungkus yang dimiliki objek atau properti dan metode prototipe dalam konstruktor.
Sintaksnya lebih sederhana daripada looping array.
Salinan kode adalah sebagai berikut:
untuk (/* inisialisasi*/ var tombol dalam objek) {
// ... kode logis
}
Kami sering menggunakan metode ini untuk beroperasi pada objek.
Salinan kode adalah sebagai berikut:
var person = {
'Nama': 'Will Wen Gunn',
'type': 'hentai',
'Keterampilan': ['pemrograman', 'fotografi', 'berbicara', 'dll']
};
untuk (tombol var secara langsung) {
nilai = orang [key];
// Jika nilainya array, konversinya menjadi string
if (value instance array) {
value = value.join (',');
}
console.log (' %s: %s', kunci, nilai);
}
/*=>
Nama: Akankah Wen Gunn
Jenis: Hentai
Keterampilan: pemrograman, fotografi, berbicara, dll
*/
Jika Anda telah menggunakan MongoDB, Anda pasti akan terbiasa dengan mekanisme kueri. Karena mekanisme permintaan MongoDB seperti jiwa API -nya, metode operasi dadih fleksibel telah memenangkan banyak popularitas dan momentum pengembangan.
Dalam implementasi Mongo API dari NanoDB, implementasi kueri menggunakan objek loop dalam skala besar.
Salinan kode adalah sebagai berikut:
var mydb = nano.db ('mydb');
var mycoll = mydb.collection ('mycoll');
var _cursor = mycoll.find ({
Ketik: 'repo',
Bahasa: 'JavaScript'
});
_cursor
.menyortir({
Bintang: 1
})
.toArray (function (err, baris) {
if (err)
return console.error (err);
console.log (baris);
});
Yang perlu kita optimalkan bukanlah loop itu sendiri, tetapi optimalisasi objek yang perlu Anda lalui.
Misalnya, kelas nanokollection di nanoDB terlihat seperti array, yang berisi semua elemen atau objek, dan menggunakan ID elemen sebagai kunci dan kemudian menyimpan elemen.
Tapi ini bukan masalahnya. Siswa yang telah menggunakan garis bawah harus mengetahui metode _.invert. Ini adalah cara yang cukup menarik untuk membalikkan kunci dan nilai -nilai objek yang diteruskan.
Salinan kode adalah sebagai berikut:
var person = {
'Nama': 'Will Wen Gunn',
'type': 'hentai'
};
var _inverted = _.invert (orang);
console.log (_inverted);
/*=>
{
'Will Wen Gunn': 'Name',
'hentai': 'tipe'
}
*/
Jika Anda perlu menggunakan objek loop untuk menanyakan nilai sifat -sifat tertentu dari objek, Anda dapat mencoba metode berikut.
Salinan kode adalah sebagai berikut:
var person = {
'Nama': 'Will Wen Gunn',
'type': 'hentai'
};
var name = 'Will Wen Gunn';
var _inverted = _.invert (orang);
if (_inverted [name] === 'name') {
Console.log ('Catched!');
}
// => ditangkap!
Namun, tidak ada banyak optimasi untuk digunakan untuk kueri objek, dan semuanya perlu didasarkan pada kebutuhan aktual. : P
Selanjutnya kita melihat dua loop lainnya, while () {} dan do {} while (). Saya percaya bahwa setiap teman yang telah menerima kursus ilmu komputer akan terbiasa dengan dua siklus ini. Satu -satunya perbedaan di antara mereka adalah urutan logis eksekusi badan loop.
Urutan eksekusi while () {} mirip dengan for () {}. Penilaian eksekusi dilakukan sebelum kode logis, tetapi kode inisialisasi dan pemrosesan dihilangkan.
Ketika suatu kondisi diberikan, kode logis dieksekusi sampai kondisi tidak lagi berlaku.
Salinan kode adalah sebagai berikut:
var sum = 0;
while (sum <10) {
jumlah + = jumlah + 1;
}
console.log (sum);
// => 15
lakukan {} while () menempatkan penilaian eksekusi setelah kode logis, yang berarti "mati dulu dan kemudian mainkan".
Salinan kode adalah sebagai berikut:
var sum = 0;
Mengerjakan {
jumlah + = jumlah + 1;
} while (sum <10);
console.log (sum);
// => 15
While () {} dan lakukan {} while () juga tidak memerlukan penghitung, tetapi gunakan kondisi tertentu untuk menentukan apakah akan mengeksekusi atau terus menjalankan kode logis.
3. While () {} dan do {} while ()
while () {} dan do {} while () terutama digunakan dalam logika bisnis, dan serangkaian operasi terus dieksekusi untuk mencapai tujuan tertentu, seperti antrian tugas.
Tetapi kedua loop ini berbahaya karena hanya dikendalikan oleh kondisi eksekusi secara default. Jika tidak ada dampak pada penilaian eksekusi dalam kode logis, loop mati akan terjadi.
Salinan kode adalah sebagai berikut:
var sum = 02
// peringatan!
while (sum <10) {
jumlah = 1 + 12
}
Kode seperti itu tidak berbeda dengan whene (true) {}, jadi sebelum digunakan, perlu untuk mengklarifikasi kondisi eksekusi dan bagaimana mempengaruhi kondisi eksekusi.
4. Manfaatkan pernyataan kontrol loop
Saya percaya bahwa semua insinyur JavaScript telah menggunakan pernyataan istirahat, tetapi pernyataan melanjutkan relatif jarang digunakan. Bahkan, ada banyak proyek open source JavaScript yang sangat baik yang dapat ditemukan.
Untuk menyelesaikan fungsi pernyataan melanjutkan, mari kita lihat kode contoh terlebih dahulu
Salinan kode adalah sebagai berikut:
// server siaran node.js
var net = membutuhkan ('net');
var util = membutuhkan ('util');
var broadcastserver = net.createServer ();
// toko klien
broadcastserver.clients = [];
// Metode siaran klien
net.socket.prototype.broadcast = function (msg) {
var klien = broadcastserver.clients;
// Dapatkan subskrip klien siaran di terpusat
var index = klien.indexOf (ini);
untuk (var i = client.length -1; i> = 0; --i) {
if (i === index) {
// Jika itu adalah klien siaran, badan loop saat ini akan diakhiri
melanjutkan;
}
Currclient = klien [i];
if (! Currclient.Destroyed) {
Currclient.write (
util.format (
'/r [echo client %s: %d] %s/ninput:',
Currclient.RemoteAddress, CurrClient.Remoteport, MSG)
);
}
}
};
// Klien baru terhubung
BroadcastServer.on ('Connection', Function (Client) {
broadcastserver.clients.push (klien);
// Selamat datang
client.write ('[server siaran] selamat datang!/ninput:');
client.broadcast (klien, 'bergabung!');
// pegangan pesan
client.on ('data', function (msg) {
client.broadcast (msg);
client.write ('/rinput:');
});
// Putuskan pegangan
client.on ('end', function () {
Client.Broadcast ('Left!');
})
});
// Mengikat
BroadcastServer.listen (8080, function () {
Console.log ('Boadcast Server Bound.');
});
Kode ini mengimplementasikan server siaran berdasarkan modul NODE.JS NET. Dalam metode siaran, kami menggunakan pernyataan melanjutkan untuk mengimplementasikan semua klien yang terhubung yang telah membuat koneksi kecuali untuk klien siaran.
Konten kode cukup sederhana. Ketika klien perlu disiarkan ke klien lain, metode siaran dari objek klien yang sesuai dengan klien dipanggil. Dalam metode siaran, program ini pertama -tama akan mendapatkan subskrip posisi klien saat ini dalam pengumpulan soket klien yang di -cache, dan kemudian loop melalui semua soket klien. Ketika penghitung loop mencapai subskrip posisi yang diperolehnya sebelumnya, kode logis di badan loop saat ini akan dilewati dan loop berikutnya akan berlanjut.
Saya percaya bahwa para insinyur yang telah mempelajari bahasa C/C ++ akan mendapatkan saran ini dari berbagai tempat: "Jangan gunakan pernyataan goto."
Pernyataan Goto yang "terkenal" ini sebenarnya adalah pengontrol aliran kode, dan rincian pernyataan GOTO tidak akan dijelaskan secara rinci di sini. Namun, tidak ada pernyataan GOTO yang jelas di JavaScript, tetapi dari pernyataan istirahat dan melanjutkan pernyataan, tidak sulit untuk menemukan bayangan Goto di JavaScript.
Ini karena pernyataan break dan lanjutan pernyataan memungkinkan penerimaan nama label yang ditentukan untuk pengalihan kode.
Mari kita lihat kode contoh yang disediakan oleh MDN.
Salinan kode adalah sebagai berikut:
var i, j;
loop1:
untuk (i = 0; i <3; i ++) {// Pernyataan pertama diberi label "loop1"
loop2:
untuk (j = 0; j <3; j ++) {// yang kedua untuk pernyataan diberi label "loop2"
if (i == 1 && j == 1) {
Lanjutkan loop1;
} kalau tidak {
console.log ("i =" + i + ", j =" + j);
}
}
}
// output adalah:
// "i = 0, j = 0"
// "i = 0, j = 1"
// "i = 0, j = 2"
// "i = 1, j = 0"
// "i = 2, j = 0"
// "i = 2, j = 1"
// "i = 2, j = 2"
// Perhatikan bagaimana melompati keduanya "i = 1, j = 1" dan "i = 1, j = 2"
Dalam kode contoh ini, loop dua lapis diimplementasikan, dan label didefinisikan di luar setiap loop, yang digunakan untuk memanggil pernyataan melanjutkan selanjutnya.
Lapisan pertama loop ada di label Loop1, yaitu, dalam program selanjutnya, jika label Loop1 dipilih dalam pernyataan Lanjutkan atau Pernyataan Break, loop terluar akan pecah.
Loop lapisan kedua ada di label loop2 di loop tingkat atas. Jika label Loop2 dipilih dalam pernyataan Lanjutkan atau Break, itu akan kembali ke badan loop loop tingkat atas.
Dengan menggunakan pernyataan kontrol loop, kami dapat mengganggu penilaian eksekusi loop asli, sehingga sistem logika yang sangat kompleks dapat dibangun. Terus terang, ada banyak pernyataan GOTO di Linux Kernel. Mengenai mengapa Anda masih sering mendengar pernyataan seperti GOTO pernyataan, cukup google mereka sendiri.
5. Loop Lanjutan
5.1 Perluas loop
Pertama -tama mari kita lihat dua potong kode, dan tebak mana yang memiliki kinerja yang lebih baik.
Salinan kode adalah sebagai berikut:
// Pengaturan
var array = [
["Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data"],
["Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data"],
["Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data"],
["Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data"],
["Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data"],
["Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data"],
["Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data"],
["Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data"]
];
proses fungsi (item) {
// Lakukan sesuatu dengan item
}
// Kasus 1
untuk (var i = array.length-1; i> = 0; i--) {
untuk (var j = array [i] .length-1; j> = 0; i--) {
proses (array [i] [j]);
}
}
// Kasus 2
untuk (var i = array.length - 1; i> = 0; i = i - 4) {
untuk (var j = array [i] .length - 1; j> = 0; j = j - 6) {
proses (array [i] [j]);
proses (array [i] [j - 1]);
proses (array [i] [j - 2]);
proses (array [i] [j - 3]);
proses (array [i] [j - 4]);
proses (array [i] [j - 5]);
}
untuk (var j = array [i - 1] .length - 1; j> = 0; j = j - 6) {
proses (array [i] [j]);
proses (array [i] [j - 1]);
proses (array [i] [j - 2]);
proses (array [i] [j - 3]);
proses (array [i] [j - 4]);
proses (array [i] [j - 5]);
}
untuk (var j = array [i - 2] .length - 1; j> = 0; j = j - 6) {
proses (array [i] [j]);
proses (array [i] [j - 1]);
proses (array [i] [j - 2]);
proses (array [i] [j - 3]);
proses (array [i] [j - 4]);
proses (array [i] [j - 5]);
}
untuk (var j = array [i - 3] .length - 1; j> = 0; j = j - 6) {
proses (array [i] [j]);
proses (array [i] [j - 1]);
proses (array [i] [j - 2]);
proses (array [i] [j - 3]);
proses (array [i] [j - 4]);
proses (array [i] [j - 5]);
}
}
Saya harus melalui semua elemen subarray dalam array. Ada dua solusi, satu adalah metode yang biasanya kami gunakan, dan yang lainnya adalah untuk memperluas tugas loop. Jawabannya adalah bahwa Kasus 2 berkinerja lebih baik, karena semua penilaian eksekusi antara setiap 6 elemen dihapus, yang secara alami lebih cepat dari biasanya.
Di sini kita melihat solusi yang lebih kuat. Jika tautan bisnis perlu diproses secara iteratif pada set data yang besar, dan volume data tidak akan berubah dari awal iterasi, maka Anda dapat mempertimbangkan menggunakan teknologi yang disebut perangkat DUFF. Teknologi ini dinamai sesuai dengan penciptanya Tom Duff, yang pertama kali diimplementasikan dalam bahasa C. Belakangan, Jeff Greenberg porting ke Javascript, dan memodifikasinya melalui Andrew b. King dan mengusulkan versi yang lebih efisien.
Salinan kode adalah sebagai berikut:
// Kredit: mempercepat situs Anda (New Riders, 2003)
var iterasi = math.floor (values.length / 8);
var leftover = values.length % 8;
var i = 0;
if (sisa> 0) {
Mengerjakan {
proses (nilai [i ++]);
} while (--leftover> 0);
}
Mengerjakan {
proses (nilai [i ++]);
proses (nilai [i ++]);
proses (nilai [i ++]);
proses (nilai [i ++]);
proses (nilai [i ++]);
proses (nilai [i ++]);
proses (nilai [i ++]);
proses (nilai [i ++]);
} while (--iterations> 0);
Prinsip kerja dari teknik ini adalah untuk menghitung panjang nilai dibagi dengan 8 untuk mendapatkan jumlah iterasi yang perlu diulang, dan menggunakan fungsi matematika.
Saya mengemas perangkat ini dan mendapatkan API dengan rasa asinkron.
Salinan kode adalah sebagai berikut:
fungsi duff (array, mapper) {
var n = math.floor (array.length / 8);
var l = array.length % 8;
var i = 0;
if (l> 0) {
Mengerjakan {
mapper (array [i ++]);
} while (--i> 0);
}
Mengerjakan {
mapper (array [i ++]);
mapper (array [i ++]);
mapper (array [i ++]);
mapper (array [i ++]);
mapper (array [i ++]);
mapper (array [i ++]);
mapper (array [i ++]);
mapper (array [i ++]);
} while (--n> 0);
}
duff ([...], fungsi (item) {
// ...
});
Berikut adalah serangkaian tes kinerja dan hasil untuk tiga solusi berulang di atas. http://jsperf.com/spreading-loop
5.2 Loop non-asli
Dalam bahasa pemrograman apa pun, loop dapat diimplementasikan tidak hanya secara tidak langsung dengan cara lain, tetapi juga dengan cara lain.
Pertama -tama mari kita tinjau beberapa konten matematika sekolah menengah - formula umum urutan.
Salinan kode adalah sebagai berikut:
Dasar
A [1] = 1
a [n] = 2 * a [n - 1] + 1
Jadi
a [n] + 1 = 2 * a [n - 1] + 2
= 2 * (a [n - 1] + 1)
(a [n] + 1) / (a [n - 1] + 1) = 2
Kemudian
a [n] + 1 = (a [n] + 1) / (a [n - 1] + 1) * (a [n - 1] + 1) / (a [n - 2] + 1) * ... * (a [2] + 1) / (a [1] + 1) * (a [i] + 1)
a [n] + 1 = 2 * 2 * ... * 2 * 2
a [n] + 1 = 2^n
a [n] = 2^n - 1
Terakhir
a [n] = 2^n - 1
Setelah membaca perhitungan sederhana di atas, Anda mungkin menebak apa yang akan kita diskusikan. Ya, kami juga dapat menerapkan loop menggunakan rekursi.
Rekursi adalah metode aplikasi yang sangat penting dalam matematika dan ilmu komputer, yang mengacu pada fungsi yang menyebut dirinya ketika digunakan.
Di komunitas Node.js, rekursi digunakan untuk mengimplementasikan teknologi yang sangat penting: teknologi middleware. Ini adalah versi baru kode implementasi middleware di WebJS yang belum dipublikasikan.
Salinan kode adalah sebagai berikut:
/**
* Metode lari Middlewares
* @param {string} url URL permintaan saat ini
* @param {objek} req objek permintaan
* @param {objek} res objek respons
* @param {function} out callback lengkap
* @return {function} server
*/
server.runmiddlewares = fungsi (url, req, res, out) {
indeks var = -1;
var middlewares = this._usingmiddlewares;
// Jalankan middleware berikutnya jika ada
function next (err) {
indeks ++;
// middleware saat ini
Var Curr = Middlewares [indeks];
if (Curr) {
var check = regexp baru (Curr.Route);
// Periksa rute
if (check.test (url)) {
mencoba {
fungsi nanti () {
Debug ('Middleware mengatakan perlu nanti %S', URL);
// Ketergantungan tidak sekarang
if (MiddleWares.Indexof (Curr)! == Middlewares.length - 1) {
_later (Curr);
indeks--;
Berikutnya();
} kalau tidak {
Debug ('A Middleware Ketergantungan Salah');
// middleware ini tidak bisa berjalan
keluar();
}
}
// Jalankan middleware
if (utils.isfunc (Curr.Handler)) {
// fungsi middleware normal
Curr.Handler (req, res, berikutnya, nanti);
} lain jika (utilsoBject (Curr.Handler) && utils.isfunc (Curr.Handler.emit)) {
// Objek server
Curr.Handler.emit ('request', req, res, berikutnya, nanti);
} kalau tidak {
// Ada yang salah tentang middleware
Berikutnya();
}
} catch (err) {
Berikutnya();
}
} kalau tidak {
Berikutnya();
}
} kalau tidak {
// keluar ke langkah berikutnya dari pipa
keluar();
}
}
// Jika middleware bergantung pada tara tengah lainnya,
// itu bisa membiarkannya nanti
fungsi _later (Curr) {
var i = middlewares.indexof (Curr);
var _tmp1 = middlewares.slice (0, i);
_tmp1.push (Middlewares [i + 1], Curr);
var _tmp2 = middlewares.slice (i + 2);
[] .push.Apply (_tmp1, _tmp2);
Middlewares = _tmp1;
}
// middleware pertama
Berikutnya();
kembalikan ini;
};
Meskipun kode ini terlihat keras dan rumit, akan jauh lebih jelas jika kita menyederhanakannya.
Salinan kode adalah sebagai berikut:
server.runmiddlewares = fungsi (url, req, res, out) {
indeks var = -1;
var middlewares = this._usingmiddlewares;
// Jalankan middleware berikutnya jika ada
function next (err) {
indeks ++;
// middleware saat ini
Var Curr = Middlewares [indeks];
if (Curr) {
var check = regexp baru (Curr.Route);
// Periksa rute
if (check.test (url)) {
// Jalankan middleware saat ini
Curr.Handler (req, res, berikutnya);
} kalau tidak {
Berikutnya();
}
} kalau tidak {
// Keluar ke langkah berikutnya dari pipa
keluar();
}
}
// middleware pertama
Berikutnya();
kembalikan ini;
};
Alasan mengapa rekursi dapat digunakan dalam implementasi sistem middleware adalah bahwa rekursi adalah metode respons aliran program yang paling cocok di Node.js.
Dalam kode implementasi middleware ini, this._usingmiddlewares adalah array loop, function next () adalah badan loop, di mana check.test (URL) adalah kondisi penilaian eksekusi, dan kode pemrosesan loop adalah penghitung indeks pertama dalam badan loop untuk bertambah dengan 1 dan fungsi berikutnya sendiri.