Saya mencoba membuat pengidentifikasi unik global dalam JavaScript. Saya tidak yakin rutinitas apa yang tersedia di semua browser, seberapa "acak" dan diunggulkan pembuat bilangan acak bawaan, dll.
GUID / UUID harus memiliki setidaknya 32 karakter dan harus tetap berada dalam kisaran ASCII untuk menghindari masalah ketika melewati mereka.
javascript
guid
uuid
Jason Cohen
sumber
sumber
Jawaban:
UUID (Pengenal Unik Universal), juga dikenal sebagai GUID (Pengenal Unik Global), menurut RFC 4122 , adalah pengidentifikasi yang dirancang untuk memberikan jaminan keunikan tertentu.
Meskipun dimungkinkan untuk mengimplementasikan UUID yang mematuhi RFC dalam beberapa baris JS ( Mis. Lihat jawaban @ broofa , di bawah) ada beberapa perangkap umum:
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
", di mana x adalah salah satu [0-9, af] M adalah salah satu [1-5], dan N adalah [8, 9, a, atau b]Math.random
)Dengan demikian, pengembang yang menulis kode untuk lingkungan produksi didorong untuk menggunakan implementasi yang ketat dan terawat dengan baik seperti modul uuid .
sumber
Untuk solusi yang sesuai dengan versi 4 RFC4122 , solusi satu-liner (ish) ini adalah yang paling ringkas yang bisa saya buat:
Pembaruan, 2015-06-02 : Perlu diketahui bahwa keunikan UUID sangat bergantung pada generator nomor acak (RNG). Solusi atas penggunaan
Math.random()
untuk singkatnya, namunMath.random()
ini tidak dijamin untuk menjadi RNG berkualitas tinggi. Lihat langganan Adam Hyland yang bagus di Math.random () untuk detailnya. Untuk solusi yang lebih kuat, pertimbangkan untuk menggunakan modul uuid , yang menggunakan API RNG dengan kualitas lebih tinggi.Pembaruan, 2015-08-26 : Sebagai catatan tambahan, inti ini menjelaskan cara menentukan berapa banyak ID yang dapat dihasilkan sebelum mencapai probabilitas tabrakan tertentu. Misalnya, dengan 3.26x10 15 versi 4 RFC4122 UUID Anda memiliki peluang tabrakan 1-dalam-sejuta.
Pembaruan, 2017-06-28 : Artikel bagus dari pengembang Chrome yang membahas kondisi kualitas PRNG Math.random di Chrome, Firefox, dan Safari. tl; dr - Pada akhir 2015 ini "cukup bagus", tetapi tidak berkualitas kriptografis. Untuk mengatasi masalah itu, berikut ini adalah versi terbaru dari solusi di atas yang menggunakan ES6,
crypto
API, dan sedikit sihir JS yang tidak dapat saya setujui untuk :Pembaruan, 2020-01-06 : Ada proposal dalam karya untuk
uuid
modul standar sebagai bagian dari bahasa JSsumber
c== 'x'
bukannyac === 'x'
. Karena jshint gagal.Saya sangat suka betapa bersihnya jawaban Broofa , tetapi sangat disayangkan implementasi yang buruk dari
Math.random
meninggalkan kesempatan untuk tabrakan.Berikut ini adalah solusi yang sesuai dengan RFC4122 versi 4 yang memecahkan masalah itu dengan mengimbangi 13 angka hex pertama dengan bagian hex stempel waktu, dan setelah offset habis oleh sebagian hex mikrodetik sejak pageload. Dengan begitu, bahkan jika
Math.random
berada pada seed yang sama, kedua klien harus menghasilkan UUID jumlah mikrodetik yang sama persis sejak pageload (jika waktu kinerja tinggi didukung) DAN pada milidetik yang sama persis (atau 10.000+ tahun kemudian) untuk dapatkan UUID yang sama:Ini biola untuk diuji.
sumber
new Date().getTime()
tidak diperbarui setiap milidetik. Saya tidak yakin bagaimana ini memengaruhi keacakan yang diharapkan dari algoritma Anda.performance.now()
tidak terbatas pada resolusi satu milidetik. Sebaliknya, mereka mewakili waktu sebagai angka floating-point dengan presisi hingga mikrodetik . Juga tidak seperti Date.now, nilai-nilai yang dikembalikan oleh performance.now () selalu meningkat pada laju yang konstan , terlepas dari jam sistem yang dapat disesuaikan secara manual atau condong oleh perangkat lunak seperti Network Time Protocol.d = Math.floor(d/16);
?Jawaban broofa cukup apik, memang - sangat pintar, benar-benar ... rfc4122 sesuai, agak mudah dibaca, dan kompak. Luar biasa!
Tetapi jika Anda melihat ekspresi reguler itu, banyak
replace()
panggilan balik,toString()
danMath.random()
panggilan fungsi (di mana dia hanya menggunakan 4 bit hasilnya dan membuang-buang sisanya), Anda mungkin mulai bertanya-tanya tentang kinerja. Memang, joelpt bahkan memutuskan untuk membuang RFC untuk kecepatan GUID generik dengannyagenerateQuickGUID
.Tapi, bisakah kita mendapatkan kecepatan dan kepatuhan RFC? Saya katakan, YA! Bisakah kita mempertahankan keterbacaan? Ya ... Tidak juga, tetapi mudah jika Anda mengikuti.
Tapi pertama-tama, hasil saya, dibandingkan dengan broofa,
guid
(jawaban yang diterima), dan yang tidak sesuai dengan rfcgenerateQuickGuid
:Jadi dengan iterasi keenam saya tentang optimisasi, saya mengalahkan jawaban paling populer dengan lebih dari 12X , jawaban yang diterima lebih dari 9X , dan jawaban cepat-tidak-sesuai dengan 2-3X . Dan saya masih rfc4122 compliant.
Tertarik bagaimana? Saya telah memasukkan sumber lengkapnya di http://jsfiddle.net/jcward/7hyaC/3/ dan di http://jsperf.com/uuid-generator-opt/4
Untuk penjelasan, mari kita mulai dengan kode broofa:
Jadi itu menggantikan
x
dengan digit hex acak,y
dengan data acak (kecuali memaksa 2 bit teratas10
sesuai dengan spesifikasi RFC), dan regex tidak cocok dengan karakter-
atau4
, jadi dia tidak harus berurusan dengan mereka. Sangat, sangat apik.Hal pertama yang perlu diketahui adalah bahwa panggilan fungsi itu mahal, seperti halnya ekspresi reguler (meskipun ia hanya menggunakan 1, ia memiliki 32 panggilan balik, satu untuk setiap pertandingan, dan di masing-masing 32 panggilan balik itu disebut Math.random () dan v. toString (16)).
Langkah pertama menuju kinerja adalah menghilangkan RegEx dan fungsi-fungsi panggilan baliknya dan menggunakan loop sederhana sebagai gantinya. Ini berarti kita harus berurusan dengan
-
dan4
karakter sedangkan broofa tidak. Juga, perhatikan bahwa kita dapat menggunakan pengindeksan String Array untuk menjaga arsitektur template String yang apik:Pada dasarnya, logika batin yang sama, kecuali kami memeriksa
-
atau4
, dan menggunakan loop sementara (bukanreplace()
panggilan balik) memberi kami peningkatan hampir 3X!Langkah selanjutnya adalah langkah kecil di desktop tetapi membuat perbedaan yang layak di ponsel. Mari kita membuat lebih sedikit panggilan Math.random () dan memanfaatkan semua bit acak itu alih-alih membuang 87% dari mereka dengan buffer acak yang digeser keluar setiap iterasi. Mari kita juga memindahkan definisi template dari loop, untuk berjaga-jaga jika itu membantu:
Ini menghemat 10-30% tergantung pada platform. Tidak buruk. Tetapi langkah besar selanjutnya menghilangkan panggilan fungsi toString bersamaan dengan optimasi klasik - tabel pencarian. Tabel pencarian 16-elemen sederhana akan melakukan pekerjaan toString (16) dalam waktu yang jauh lebih singkat:
Optimasi berikutnya adalah klasik lain. Karena kita hanya menangani 4-bit output di setiap iterasi loop, mari kita memotong jumlah loop menjadi dua dan memproses 8-bit setiap iterasi. Ini rumit karena kita masih harus menangani posisi bit yang sesuai dengan RFC, tetapi itu tidak terlalu sulit. Kami kemudian harus membuat tabel pencarian yang lebih besar (16x16, atau 256) untuk menyimpan 0x00 - 0xff, dan kami membangunnya hanya sekali, di luar fungsi e5 ().
Saya mencoba e6 () yang memproses 16-bit pada suatu waktu, masih menggunakan LUT 256-elemen, dan itu menunjukkan hasil optimasi yang semakin berkurang. Meskipun memiliki iterasi yang lebih sedikit, logika bagian dalam diperumit oleh peningkatan pemrosesan, dan ia melakukan hal yang sama pada desktop, dan hanya ~ 10% lebih cepat di ponsel.
Teknik optimalisasi akhir untuk diterapkan - membuka gulungan lingkaran. Karena kita mengulang-ulang beberapa kali, kita secara teknis dapat menulis ini dengan tangan. Saya mencoba ini sekali dengan variabel acak tunggal r yang saya terus menetapkan ulang, dan kinerja mabuk. Tetapi dengan empat variabel ditugaskan data acak di depan, kemudian menggunakan tabel pencarian, dan menerapkan bit RFC yang tepat, versi ini merokok semuanya:
Dimodernisasi: http://jcward.com/UUID.js -
UUID.generate()
Lucunya, menghasilkan 16 byte data acak adalah bagian yang mudah. Seluruh trik mengekspresikannya dalam format String dengan kepatuhan RFC, dan itu paling ketat dicapai dengan 16 byte data acak, loop terbuka dan tabel pencarian.
Saya harap logika saya benar - sangat mudah untuk membuat kesalahan dalam jenis pekerjaan yang membosankan ini. Tapi hasilnya terlihat bagus untuk saya. Saya harap Anda menikmati perjalanan gila ini melalui optimasi kode!
Maklum: tujuan utama saya adalah menunjukkan dan mengajarkan strategi optimasi yang potensial. Jawaban lain mencakup topik-topik penting seperti tabrakan dan angka acak, yang penting untuk menghasilkan UUID yang baik.
sumber
Math.random()*0xFFFFFFFF
baris harusMath.random()*0x100000000
untuk keacakan penuh, dan>>>0
harus digunakan alih-alih|0
untuk menjaga nilai-nilai tidak ditandatangani (meskipun dengan kode saat ini saya pikir itu akan baik-baik saja meskipun sudah ditandatangani). Akhirnya akan menjadi ide yang sangat bagus hari ini untuk digunakanwindow.crypto.getRandomValues
jika tersedia, dan kembali ke Math.random hanya jika benar-benar diperlukan. Math.random mungkin memiliki kurang dari 128 bit entropi, dalam hal ini akan lebih rentan terhadap benturan daripada yang diperlukan.Berikut adalah beberapa kode berdasarkan RFC 4122 , bagian 4.4 (Algoritma untuk Membuat UUID dari Truly Random atau Pseudo-Random Number).
sumber
var s = new Array(36);
Tampilkan cuplikan kode
Jika ID yang dihasilkan lebih dari 1 milidetik terpisah, mereka 100% unik.
Jika dua ID dihasilkan dengan interval yang lebih pendek, dan dengan asumsi bahwa metode acak benar-benar acak, ini akan menghasilkan ID yang 99,9999999999999999% cenderung unik secara global (tabrakan dalam 1 dari 10 ^ 15)
Anda dapat meningkatkan angka ini dengan menambahkan lebih banyak digit, tetapi untuk menghasilkan 100% ID unik, Anda harus menggunakan penghitung global.
jika Anda memerlukan kompatibilitas RFC, format ini akan lulus sebagai GUID versi 4 yang valid:
Tampilkan cuplikan kode
Sunting: Kode di atas mengikuti niat, tetapi bukan huruf RFC. Di antara perbedaan lainnya adalah beberapa angka acak pendek. (Tambahkan lebih banyak angka acak jika Anda membutuhkannya) Sisi baiknya adalah ini sangat cepat :) Anda dapat menguji validitas GUID Anda di sini
sumber
[slug, date, random].join("_")
untuk membuatusr_1dcn27itd_hj6onj6phr
. Itu membuatnya id juga berfungsi sebagai bidang "dibuat pada"GUID tercepat seperti metode generator string dalam format
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
. Ini tidak menghasilkan GUID yang memenuhi standar.Sepuluh juta eksekusi dari implementasi ini hanya membutuhkan 32,5 detik, yang merupakan yang tercepat yang pernah saya lihat di browser (satu-satunya solusi tanpa loop / iterasi).
Fungsi ini sesederhana:
Untuk menguji kinerja, Anda dapat menjalankan kode ini:
Saya yakin sebagian besar dari Anda akan mengerti apa yang saya lakukan di sana, tetapi mungkin ada setidaknya satu orang yang perlu penjelasan:
Algoritma:
Math.random()
mengembalikan fungsi angka desimal antara 0 dan 1 dengan 16 digit setelah titik pecahan desimal (misalnya0.4363923368509859
).0.6fb7687f
).Math.random().toString(16)
.0.
awalan (0.6fb7687f
=>6fb7687f
) dan mendapatkan string dengan delapan karakter heksadesimal.(Math.random().toString(16).substr(2,8)
.Math.random()
fungsi akan mengembalikan angka yang lebih pendek (misalnya0.4363
), karena nol di akhir (dari contoh di atas, sebenarnya angkanya0.4363000000000000
). Itu sebabnya saya menambahkan string ini"000000000"
(string dengan sembilan nol) dan kemudian memotongnya dengansubstr()
fungsi untuk membuatnya menjadi sembilan karakter persis (mengisi nol di sebelah kanan).Math.random()
fungsi akan mengembalikan tepat 0 atau 1 (probabilitas 1/10 ^ 16 untuk masing-masing). Itu sebabnya kami perlu menambahkan sembilan nol padanya ("0"+"000000000"
atau"1"+"000000000"
), dan kemudian memotongnya dari indeks kedua (karakter ke-3) dengan panjang delapan karakter. Untuk sisa kasus, penambahan nol tidak akan membahayakan hasilnya karena tetap memotongnya.Math.random().toString(16)+"000000000").substr(2,8)
.Perakitan:
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
.XXXXXXXX
dan-XXXX-XXXX
.XXXXXXXX
-XXXX-XXXX
-XXXX-XXXX
XXXXXXXX
._p8(s)
,s
parameter memberitahu fungsi apakah akan menambahkan tanda hubung atau tidak._p8() + _p8(true) + _p8(true) + _p8()
dan mengembalikannya.Tautkan ke posting ini di blog saya
Nikmati! :-)
sumber
Berikut adalah kombinasi dari jawaban terpilih teratas , dengan solusi untuk tabrakan Chrome :
Di jsbin jika Anda ingin mengujinya.
sumber
, does not keep the Version 4 UUIDs format defined by RFC 4122. That is instead of
xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx` yang dihasilkannyaxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
.Berikut ini adalah implementasi yang benar-benar tidak sesuai tetapi sangat berkinerja untuk menghasilkan pengidentifikasi unik seperti GUID yang aman seperti ASCII.
Menghasilkan 26 [a-z0-9] karakter, menghasilkan UID yang lebih pendek dan lebih unik daripada GUID yang mematuhi RFC. Tanda hubung dapat ditambahkan dengan sepele jika hal-hal yang mudah dibaca oleh manusia.
Berikut adalah contoh penggunaan dan pengaturan waktu untuk fungsi ini dan beberapa jawaban lain dari pertanyaan ini. Waktunya dilakukan di bawah Chrome m25, masing-masing 10 juta iterasi.
Ini kode waktu.
sumber
Berikut adalah solusi tertanggal 9 Oktober 2011 dari komentar oleh pengguna jed di https://gist.github.com/982883 :
Ini mencapai tujuan yang sama dengan jawaban berperingkat tertinggi saat ini , tetapi dalam 50+ lebih sedikit byte dengan mengeksploitasi paksaan, rekursi, dan notasi eksponensial. Bagi mereka yang penasaran bagaimana cara kerjanya, berikut adalah bentuk dari versi yang lebih tua dari fungsi:
sumber
Dari blog teknis sagi shkedy :
Ada metode lain yang melibatkan menggunakan kontrol ActiveX, tetapi menjauhlah dari ini!
Sunting: Saya pikir perlu menunjukkan bahwa tidak ada generator GUID yang dapat menjamin kunci unik (lihat artikel wikipedia ). Selalu ada kemungkinan tabrakan. GUID hanya menawarkan semesta kunci yang cukup besar untuk mengurangi perubahan tabrakan menjadi hampir nol.
sumber
Anda dapat menggunakan simpul-uuid ( https://github.com/kelektiv/node-uuid )
Sederhana, pembuatan cepat RFC4122 UUIDS.
Fitur:
Instal Menggunakan NPM:
Atau Menggunakan uuid melalui browser:
Unduh Raw File (uuid v1): https://raw.githubusercontent.com/kelektiv/node-uuid/master/v1.js Unduh Raw File (uuid v4): https://raw.githubusercontent.com/kelektiv/node -uuid / master / v4.js
Ingin lebih kecil? Lihat ini: https://gist.github.com/jed/982883
Pemakaian:
ES6:
sumber
EDIT:
Tinjau kembali proyek saya yang menggunakan fungsi ini dan tidak menyukai verbositasnya. - Tapi perlu keacakan yang tepat.
Versi yang didasarkan pada jawaban Briguy37 dan beberapa operator bitwise untuk mengekstrak jendela berukuran menggigit dari buffer.
Harus mematuhi skema RFC Type 4 (acak), karena saya memiliki Masalah terakhir kali parsing uuids tidak sesuai dengan UUID Jawa.
sumber
Modul JavaScript sederhana sebagai kombinasi jawaban terbaik di utas ini.
Pemakaian:
sumber
GUID
sebagaistring
. Jawaban Anda setidaknya menangani penyimpanan yang jauh lebih efisien menggunakan aUint16Array
. ThetoString
Fungsi harus menggunakan representasi biner dalam JavaScriptobject
Ini membuat UUID versi 4 (dibuat dari angka acak semu):
Berikut adalah contoh UUID yang dihasilkan:
sumber
Yah, ini sudah memiliki banyak jawaban, tetapi sayangnya tidak ada acak "benar" dalam kelompok itu. Versi di bawah ini merupakan adaptasi dari jawaban broofa, tetapi diperbarui untuk menyertakan fungsi acak "benar" yang menggunakan pustaka crypto di mana tersedia, dan fungsi Alea () sebagai fallback.
sumber
Proyek JavaScript di GitHub - https://github.com/LiosK/UUID.js
sumber
sumber
Saya ingin memahami jawaban broofa, jadi saya mengembangkannya dan menambahkan komentar:
sumber
Menyesuaikan generator UUID / GUID saya sendiri dengan beberapa tambahan di sini .
Saya menggunakan Kybos berikut generator nomor acak untuk menjadi sedikit lebih kriptografis suara.
Di bawah ini adalah skrip saya dengan metode Mash dan Kybos dari baagoe.com dikecualikan.
sumber
Bagi mereka yang menginginkan solusi yang sesuai versi rfc4122 dengan pertimbangan kecepatan (beberapa panggilan ke Math.random ()):
Fungsi di atas harus memiliki keseimbangan yang layak antara kecepatan dan keacakan.
sumber
Sampel ES6
sumber
Cara yang lebih baik:
Diperkecil:
sumber
Saya tahu, ini pertanyaan lama. Hanya untuk kelengkapan, jika lingkungan Anda adalah SharePoint, ada fungsi utilitas yang disebut
SP.Guid.newGuid
( tautan msdn ) yang membuat panduan baru. Fungsi ini ada di dalam file sp.init.js. Jika Anda menulis ulang fungsi ini (untuk menghapus beberapa dependensi lainnya dari fungsi pribadi lainnya), sepertinya ini:sumber
Yang ini didasarkan pada tanggal, dan menambahkan akhiran acak untuk "memastikan" keunikan. Bekerja dengan baik untuk pengidentifikasi css. Selalu mengembalikan sesuatu seperti dan mudah diretas:
uid-139410573297741
sumber
Kode sederhana yang digunakan
crypto.getRandomValues(a)
pada browser yang didukung (IE11 +, iOS7 +, FF21 +, Chrome, Android Chrome). Hindari penggunaanMath.random()
karena dapat menyebabkan tabrakan (misalnya 20 tabrakan untuk 4000 uuids yang dihasilkan dalam situasi nyata oleh Muxa ).Catatan:
sumber
Jika Anda hanya membutuhkan string 128 bit acak tanpa format tertentu, Anda dapat menggunakan:
Yang akan mengembalikan sesuatu seperti
2350143528-4164020887-938913176-2513998651
.sumber
Array.from((window.crypto || window.msCrypto).getRandomValues(new Uint32Array(4))).map(n => n.toString(16)).join('-')
Hanya varian lain yang lebih mudah dibaca dengan hanya dua mutasi.
sumber
OK, menggunakan paket uuid , mendukung untuk UUID versi 1, 3, 4 dan 5 :
lalu:
Anda juga dapat melakukannya dengan opsi yang ditentukan sepenuhnya:
Untuk info lebih lanjut, kunjungi halaman npm di sini
sumber
Adalah penting bahwa untuk menggunakan kode yang teruji dengan baik yang dikelola oleh lebih dari 1 kontributor alih-alih mencambuk barang-barang Anda sendiri untuk ini. Ini adalah salah satu tempat di mana Anda mungkin ingin lebih suka kode yang paling stabil daripada versi pandai yang sesingkat mungkin yang bekerja di browser X tetapi tidak memperhitungkan keanehan akun Y yang sering menyebabkan sangat sulit untuk menyelidiki bug daripada memanifestasikan hanya secara acak untuk beberapa pengguna. Secara pribadi saya menggunakan uuid-js di https://github.com/aurigadl/uuid-js yang mengaktifkan bower agar saya dapat mengambil pembaruan dengan mudah.
sumber