biner data
Semua konten di komputer: teks, angka, gambar, audio, dan video pada akhirnya akan diwakili oleh biner.
JS
dapat langsung memproses data yang sangat intuitif: seperti string. Kami biasanya menampilkan konten ini kepada pengguna,
tetapi Anda mungkin mengira JS It juga dapat memproses gambar.
JS
HTML
memberi tahu browser alamat gambar tersebutNamun, berbeda untuk server,
utf-8
, tetapi dengan GBK
. kita harus membacanya. Data biner tersebut kemudian diubah menjadi teks yang sesuai melalui GKB.sharp
di Node, yang bertanggung jawab untuk membaca gambar atau Buffer
dari gambar yang masuk dan kemudian memprosesnya.Node
, koneksi panjang dibuat melalui TCP
stream. Kita perlu Data diubah menjadi byte sebelum diteruskan, dan ukuran byte yang dikirimkan perlu diketahui (klien perlu menilai berapa banyak konten yang akan dibaca berdasarkan ukurannya)Buffer dan Biner
Kita akan menemukannya untuk pengembangan front-end, biasanya jarang berhubungan dengan biner Berurusan satu sama lain, tetapi untuk sisi server, untuk mengimplementasikan banyak fungsi, kita harus langsung mengoperasikan data binernya.
Oleh karena itu, untuk memudahkan pengembang menyelesaikan lebih banyak fungsi , Node
memberi kita kelas bernama Buffer
, dan bersifat global. Seperti yang
kami katakan sebelumnya, data biner disimpan di Buffer, jadi bagaimana cara menyimpannya?
8
-bit: 00000000
, yang mana persisnya satu byte.
1 byte = 8 bit
byte
1 byte = 8 bit
, 1kb = 1024 byte
, 1M = 1024kb
, 1 G = 1024 M
TCP
int
dalam banyak bahasa pemrograman adalah 4
byte, dan tipe long
adalah 8
byteRGB
masing-masing adalah 255
, jadi intinya,Buffer dan string
Buffer
disimpan dengan satu byte di komputer, yaitu setara dengan array byte. Setiap item dalam array berukuran satu byte.
Jika kita ingin memasukkan string ke dalam Buffer, bagaimana prosesnya?
buffer
.const message = 'Hello'. // Gunakan kata kunci baru untuk membuat instance buffer, tetapi metode pembuatan ini telah kedaluwarsa const buffer = new Buffer(message) konsol.log(penyangga); // <Penyangga 48 65 6c 6c 6f> console.log(buffer.toString()); //
Pengkodean dan pengodean string bahasa Mandarin yang terhormat.
buffer
adalah utf-8
, jadi dalam kode berikut, kelas Buffer
menggunakan pengkodean utf-8 untuk mengkodekan string kita , kami juga menggunakan utf-8 untuk memecahkan kode string kami.3
byteconst message = 'Hello' // Gunakan Buffer.from untuk memecahkan kode string kita const buffer = Buffer.from(message) konsol.log(buffer); // <Buffer e4 bd a0 e5 a5 bd e5 95 8a> // Ada metode toString dalam instance buffer yang dapat mendekode pengkodean console.log(buffer.toString()); // 'Halo'
, apa yang akan terjadi jika pengkodean dan dekode menggunakan bentuk hasil pengkodean yang berbeda?
const message = 'Halo' const buffer = Buffer.from(pesan, 'utf16le') konsol.log(penyangga); // <Penyangga 60 4f 7d 59 4a 55> console.log(buffer.toString()); // `O}YJU
Cara lain untuk membuat Buffer
Ada banyak cara untuk membuat buffer
. Di sini kita dapat membuat Buffer
melalui alloc
Kita dapat langsung membuat instance buffer dalam bentuk array
otomatis
akan
Misalnya, jika 8 dilewatkan di sini, maka buffer yang dibuat akan memiliki 8 elemen, dan bilangan biner yang sesuai dengan setiap elemen adalah 0. const buffer = Buffer.alloc(8) konsol.log(penyangga); // <Penyangga 00 00 00 00 00 00 00 00> // Jika nilai ditetapkan ke angka desimal, buffer akan membantu kita mengubahnya menjadi angka heksadesimal dan kemudian menuliskannya ke lokasi yang sesuai buffer[0] = 88 // Di js, apa pun yang dimulai dengan 0x direpresentasikan sebagai buffer bilangan heksadesimal[1] = 0x88 console.log(buffer); // <Buffer 58 88 00 00 00 00 00 00>
Operasi buffer dan file
1. Jika file teks
buffer
asli akan dikembalikan secara langsung , yang merupakan hasil konten file utf-8
yang dikodekan bilangan binerconst fs = require('fs') fs.readFile('./a.txt', (err, data) => { konsol.log(data); // <Penyangga e5 93 88 e5 93 88> })
const fs = require('fs') // pengkodean menunjukkan pengkodean karakter yang digunakan untuk decoding, dan pengkodean default ke utf-8 fs.readFile('./a.txt', { pengkodean: 'utf-8' }, (err, data) => { console.log(data); // Haha})
const fs = require('fs') // Pengkodeannya menggunakan pengkodean karakter utf16le, dan penguraiannya menggunakan format utf-8. Pasti penguraiannya salah. , data) => { konsol.log(data); // Kesalahan }) // Kode di atas mirip dengan kode berikut const msg = 'Haha' const buffer = Buffer.from(pesan, 'utf-8') console.log(buffer.toString('utf16le')); //
2. File gambar
menyalin pengkodean gambar untuk mencapai tujuan menyalin gambar.
encoding
, karena pengkodean karakter hanya dibaca saat membaca gambar. Ini hanya berguna saat mengambil file teks. fs.readFile('./logo.png', (err, data) => { console.log(data); // Yang dicetak adalah pengkodean biner yang sesuai dengan file gambar // Kita juga dapat menulis pengkodean gambar ke file lain, yang setara dengan kita menyalin gambar fs.writeFile(' ./bar .png', data, salah => { konsol.log(err); }) })
sharp
const sharp = require('sharp') // Pangkas gambar logo.png menjadi 200x300 dan salin ke file bax.png sharp('./logo.png') .mengubah ukuran(200, 300) .toFile('./bax.png', (err, info) => { konsol.log(err); }) // Anda juga dapat mengonversi file gambar menjadi buffer terlebih dahulu, lalu menulisnya ke file tersebut. Anda juga dapat menyalin gambar sharp('./logo.png') .mengubah ukuran(300, 300) .toBuffer() .lalu(data => { fs.writeFile('./baa.png', data, err => { konsol.log(err); }) })
Proses pembuatan Buffer
Buffer
, kita tidak akan sering menggunakan memori dari sistem operasi. Secara default, pertama-tama akan diterapkan pada memori 8 * 1024
byte, yaitu 8kb
Apa itu perulangan peristiwa?
Apa itu perulangan acara?
JS
yang kita tulis dan browser atau Node
.JS
yang kita tulis dan panggilan API browser ( setTimeout
, AJAX
,监听事件
, dll. ) Bridge berkomunikasi melalui fungsi panggilan balik.file system
, networ
, dll.).Proses dan thread
Proses dan thread adalah dua konsep dalam sistem operasi:
process
): program yang dijalankan komputerthread
): unit terkecil di mana sistem operasi dapat menjalankan jadwal perhitungan, sehingga CPU
dapat langsung beroperasi thread, yangterdengar sangat abstrak, mari kita jelaskan secara intuitif:
Mari kita gunakan contoh nyata untuk menjelaskan
sistem operasi
pengembangan multi-proses yang multi-proses
, dan memeriksa informasi) bekerja pada waktu yang sama?
CPU
sangat cepat, dan dapat dengan cepat beralih di antara beberapa proses.Browser dan JavaScript
Kita sering mengatakan bahwa JavaScript
adalah single-thread, tetapi thread JS harus memiliki proses containernya sendiri Node
Apakah browser atau browser Node merupakan suatu proses?
tab
, proses baru akan dimulai. Hal ini untuk mencegah satu halaman macet dan menyebabkan semua halaman menjadi tidakNamun, eksekusi kode JavaScript dijalankan di thread terpisah.
JS
hanya dapat melakukan satu hal pada saat yangproses eksekusi JavaScript
tidak akan dieksekusi sampai dimasukkan ke dalam tumpukan panggilan fungsi. Mari kita analisis proses eksekusi kode
const message = 'Hello World'. console.log(pesan); fungsi jumlah(angka1, angka2) { kembalikan nomor1 + nomor2 } fungsi foo() { hasil const = jumlah(20, 30) console.log(hasil); } foo()
main
seperti bahasa pemrograman lainnyamessage
log
fungsi akan ditempatkan Masukkan tumpukan pemanggilan fungsi. Setelah eksekusi, keluarkan tumpukanfoo
. Fungsi foo dimasukkan ke dalam tumpukan pemanggilan fungsi. Namun, fungsi sum
perlu dipanggil selama eksekusi,js
dijalankan, dan fungsi utama dikeluarkan dariloop peristiwa browser
. Bagaimana jika ada operasi asinkron selama eksekusi kode JS
?
setTimeout
di tengahberikutnya (kami menyebutnya fungsi timer
), kapan akan dieksekusi?
web api
. Browser akan menyimpan fungsi panggilan balik terlebih dahulu. Pada waktu yang tepat, fungsi pengatur waktu akan ditambahkan ke antrian acaraMengapa setTimeout tidak memblokir eksekusi kode
Itu karena browser menyimpan hal yang sangat, sangat penting -
browser loop peristiwa akan membantu kita menyimpan fungsi panggilan balik di setTimeout dengan cara tertentu. Metode yang lebih umum adalah menyimpannya di pohon merah-hitam
dan menunggu hingga setTimeout dijadwalkan Ketika waktu pengatur waktu tiba, fungsi panggilan balik pengatur waktu akan dikeluarkan dari tempat yang disimpan dan dimasukkan ke dalam antrian acara.
Setelah loop acara menemukan bahwa ada sesuatu dalam antrian kita, dan tumpukan panggilan fungsi saat ini kosong, lainnya
tentu saja
, fungsi berikutnya tidak akan dimasukkan ke dalam tumpukan sampai fungsi sebelumnya dalam antrean muncul).
, tidak ada Harus ada hanya satu peristiwa. Misalnya, selama proses tertentu, pengguna mengklik tombol di browser. Kita mungkin memiliki monitor untuk mengklik tombol ini, yang sesuai dengan fungsi panggilan balik tersebut juga akan ditambahkan ke dalam antrian kami, urutan eksekusi didasarkan pada urutan mereka dalam antrian acara. Ada juga ringkasan panggilan balik yang kami kirimkan permintaan ajax
ke antrian acara
: Sebenarnya, perulangan acara adalah hal yang sangat sederhana Artinya, ketika panggilan balik tertentu perlu dijalankan dalam situasi khusus, panggilan balik itu akan disimpan in advance dimasukkan ke dalam antrian acara, dan loop acara mengeluarkannya dan memasukkannya ke dalam tumpukan panggilan fungsi.
Tugas makro dan tugas mikro.
macrotask queue
, loop peristiwa tidak hanya mempertahankan satu antrian. Faktanya, ada dua antrian, dan pelaksanaan tugas dalam antrian harus menunggu
ajax
setTimeout
, setInterval
, pemantauan DOM
, UI Rendering
danmicrotask queue
): Promise
then
callback, Mutation Observer API
, queueMicrotask()
, dll.Jadi apa prioritas dari dua antrian di loop acara?
main script
dijalankan terlebih dahulu (kode skrip tingkat atas ditulis).dahulu
Poin pengujian: main stcipt
, setTimeout
, Promise
, then
, queueMicrotask
setTimeout(() => { konsol.log('set1');4 Janji baru(putuskan => { menyelesaikan() }).lalu(putuskan => { Janji baru(putuskan => { menyelesaikan() }).lalu(() => { konsol.log('lalu4'); }) konsol.log('lalu2'); }) }) Janji baru(putuskan => { konsol.log('pr1'); menyelesaikan() }).lalu(() => { konsol.log('lalu1'); }) setWaktu habis(() => { konsol.log('set2'); }) konsol.log(2); antrianMicrotask(() => { console.log('queueMicrotask'); }) Janji baru(putuskan => { menyelesaikan() }).lalu(() => { konsol.log('lalu3'); }) // pr1 // 2 //lalu1 //antrianMicrotask //lalu3 // set1 //lalu2 //lalu4 // set2
setTimeout
akan segera dimasukkan ke dalam tumpukan panggilan fungsi, dan akan segera dikeluarkan dari tumpukan setelah eksekusi. Fungsi timer
akan dimasukkan ke dalam antrian tugas makro.
Fungsi yang diteruskan ke kelas Promise
akan segera dieksekusi. Ini bukan fungsi panggilan balik, jadi akan dicetak pr1
, dan karena metode resolve
dijalankan, status Janji akan segera berubah menjadi fulfilled
, sehingga ketika fungsi then
dijalankan, fungsi panggilan baliknya akan sesuai. dimasukkan ke dalam antrian tugas mikro dan
fungsi setTimeout ditemui lagi. Ketika tumpukan muncul, fungsi pengatur waktunya akan dimasukkan ke dalam antrian tugas makro
2
menemukan pernyataan console.log
dicetak, dan kemudian muncul.
Suatu fungsi terikat ke queueMicrotask
di sini, dan fungsi tersebut akan ditempatkan Setelah memasuki antrian microtask,
pernyataan Promise baru ditemukan, tetapi segera mengubah status janji menjadi terpenuhi, sehingga panggilan balik yang sesuai dengan fungsi kemudian juga dimasukkan ke dalam antrian tugas mikro
karena kode skrip sinkronisasi telah dijalankan, sekarang acara Di awal perulangan, tugas yang bersaing dengan antrian tugas mikro dan tugas makro dimasukkan ke dalam antrian tugas mikro. tumpukan panggilan fungsi dalam urutan prioritas. Catatan: Prioritas tugas mikro lebih tinggi daripada tugas makro. Anda harus membacanya setiap kali sebelum ingin menjalankan tugas makro. Periksa apakah antrian tugas mikro kosong itu tidak kosong, Anda perlu menjalankan tugas antrian microtask terlebih dahulu.
Microtask pertama adalah mencetak then1
, microtask kedua adalah mencetak queueMicrotask, dan microtask ketiga adalah mencetak then3
. mulai menjalankan tugas makro.
Tugas makro pertama lebih rumit. Pertama-tama ia akan mencetak set1
, lalu menjalankan pernyataan new promise
yang segera mengubah status. Panggilan baliknya akan dimasukkan ke dalam antrian tugas mikro Antriannya tidak kosong, jadi antrian microtask dengan prioritas lebih tinggi perlu dieksekusi, yang setara dengan panggilan balik kemudian yang segera dieksekusi. Ini adalah pernyataan Promise baru yang sama, dan swap yang sesuai dimasukkan ke dalam antrian microtask. Perhatikan bahwa ada fungsi console
setelah pernyataan Promise baru. Fungsi ini akan segera dijalankan setelah pernyataan Promise baru dijalankan, yaitu mencetak then2
. Masih ada tugas dalam konfrontasi microtask, jadi langkah selanjutnya adalah mencetak then4
. Sejauh ini antrian microtask masih kosong, dan antrian macrotask dapat terus dieksekusi
, sehingga set2
macrotask berikutnya akan dicetak. Setelah macrotask dijalankan,
hasil pencetakan seluruh kode adalah: pr1 -> 2 -> then1 -> queueMicrotask -> then3 -> set1 -> then2 -> then4 -> set2
Pertanyaan wawancara <2>
Poin tes: main script
, setTimeout
, Promise
, then
, queueMicrotask
, await
async
suplemen pengetahuan async: async, menunggu adalah gula sintaksis untuk Promise
. Saat menangani masalah perulangan peristiwa,
new Promise((resolve,rejcet) => { 函数执行})
then(res => {函数执行})
di Janji sebelumnyaasync function async1() { console.log('async1 mulai'); menunggu async2() console.log('async1 akhir'); } fungsi asinkron async2() { konsol.log('async2'); } console.log('skrip mulai'); setWaktu habis(() => { console.log('setTimeout'); }, 0) async1() Janji baru(putuskan => { console.log('janji1'); menyelesaikan() }).lalu(() => { console.log('janji2'); }) console.log('akhir skrip'); // skrip dimulai // async1 mulai // asinkron2 // janji1 // skrip berakhir // async1 berakhir // janji2 // setTimeout
adalah definisi fungsi di awal, dan tidak perlu dimasukkan ke dalam tumpukan panggilan fungsi untuk dieksekusi hingga menemukan pernyataan console
pertama. Setelah mendorong tumpukan, jalankan script start
dan kemudian keluarkan dari tumpukan
untuk menemukan fungsi setTimeout
pertama, yang sesuai dengan timer
akan dimasukkan ke dalam antrian tugas makro
dan fungsi async1 akan dieksekusi. Pertama, async1 start
akan dicetak, dan kemudian fungsi async2
setelah pernyataan await
akan dieksekusi. Karena seperti yang disebutkan sebelumnya, fungsi setelah kata kunci menunggu dianggap new Promise
, fungsi ini akan segera dieksekusi, sehingga async2 akan dicetak, tetapi kode setelah pernyataan menunggu setara dengan dimasukkan ke dalam kemudian. panggilan balik, artinya, console.log('async1 end')
Baris kode ini dimasukkan ke dalam antrian tugas mikro
dan kode terus dijalankan. Ia menemukan pernyataan Promise baru, sehingga promise1
segera dicetak kemudian panggilan balik dimasukkan ke dalam antrian tugas mikro untuk
menjalankan
fungsi konsol terakhir untuk pencetakan. script end
, kode sinkronisasi telah dijalankan. Loop peristiwa akan menuju ke tugas makro dan antrian tugas mikro untuk menjalankan tugas
antrian tugas. Pernyataan cetak yang sesuai dengan tugas mikro pertama akan dieksekusi, yang berarti async1 end
akan dicetak, dan kemudian promise2
dicetak. Pada saat ini, antrian tugas mikro kosong, dan tugas-tugas dalam antrian tugas makro dimulai dijalankan.
SetTimeout yang sesuai dengan fungsi pengatur waktu akan dicetak. Pada saat ini, tugas makro juga dijalankan, dan urutan pencetakan terakhir adalah: script start -> async1 start -> async2 -> promise1 -> script end -> async1 end -> promise2 -> setTimeout