data binary
All content in the computer: text, numbers, pictures, audio, and video will eventually be represented by binary.
JS
can directly process very intuitive data: such as strings. We usually display these contents to users,
but you may think that JS It can also process images.
JS
or HTML
to the browser. It is only responsible for telling the browser the address of the image.However, It is different for the server.
utf-8
, but with GBK
, then we must read their The binary data is then converted into corresponding text through GKB.sharp
in Node, which is responsible for reading pictures or Buffer
of incoming pictures and then processing them.Node
, a long connection is established through TCP
. TCP transmits a byte stream. We need to The data is converted into bytes before being passed in, and the size of the transmitted bytes needs to be known (the client needs to judge how much content to read based on the size)Buffer and Binary
We will find that for front-end development, it is usually rarely related to binary Dealing with each other, but for the server side, in order to implement many functions, we must directly operate its binary data.
Therefore, in order to facilitate developers to complete more functions, Node
provides us with a class named Buffer
, and it is global As
we said before, binary data is stored in the Buffer, so how is it stored?
8
-bit binary: 00000000
, which is exactly one byte. Why is it 8-bit?
byte
. )1 byte = 8 bit
, 1kb = 1024 byte
, 1M = 1024kb
, 1 G = 1024 M
int
type in many programming languages is 4
bytes, and the long
type is 8
bytes.TCP
transmitsRGB
are 255
respectively, so in essence,the Buffer and the string
Buffer
are stored with one byte in the computer, which is equivalent to a An array of bytes. Each item in the array is one byte in size.
If we want to put a string into a Buffer, what is the process?
buffer
instance.const message = 'Hello' // Use the new keyword to create a buffer instance, but this creation method has expired const buffer = new Buffer(message) console.log(buffer); // <Buffer 48 65 6c 6c 6f> console.log(buffer.toString()); // Hello
Chinese string encoding and decoding.
buffer
is utf-8
, so in the following code, the Buffer
class uses utf-8 encoding to encode our string. Encoding, we also use utf-8 to decode our strings.3
byte binary encodingconst message = 'Hello' // Use Buffer.from to decode our string const buffer = Buffer.from(message) console.log(buffer); // <Buffer e4 bd a0 e5 a5 bd e5 95 8a> // There is a toString method in the buffer instance that can decode the encoding console.log(buffer.toString()); // 'Hello'
, what will happen if encoding and decoding use different forms of encoding results?
const message = 'Hello' const buffer = Buffer.from(message, 'utf16le') console.log(buffer); // <Buffer 60 4f 7d 59 4a 55> console.log(buffer.toString()); // `O}YJU
Other ways to create Buffers
There are many ways to create buffer
. Here we can create Buffer
through alloc
We can directly create buffer instances in the form of arrays for each One bit is modified.
// which can specify our buffer. Number of digits. For example, if 8 is passed in here, then the created buffer will have 8 elements, and the binary number corresponding to each element is 0. const buffer = Buffer.alloc(8) console.log(buffer); // <Buffer 00 00 00 00 00 00 00 00> // If the value is assigned to a decimal number, the buffer will help us convert it to a hexadecimal number and then write it to the corresponding location buffer[0] = 88 // In js, anything starting with 0x is represented as a hexadecimal number buffer[1] = 0x88 console.log(buffer); // <Buffer 58 88 00 00 00 00 00 00>
Buffer and file operations
1. If the text file
buffer
will be returned directly, which is the file content result. utf-8
encoded binary numberconst fs = require('fs') fs.readFile('./a.txt', (err, data) => { console.log(data); // <Buffer e5 93 88 e5 93 88> })
const fs = require('fs') // encoding indicates the character encoding used for decoding, and the encoding defaults to utf-8 fs.readFile('./a.txt', { encoding: 'utf-8' }, (err, data) => { console.log(data); // Haha})
const fs = require('fs') // The encoding uses utf16le character encoding, and the decoding uses utf-8 format. It must be that the decoding is not correct. fs.readFile('./a.txt', { encoding: 'utf16le' }, (err, data) => { console.log(data); // Error }) // The above code is similar to the following code const msg = 'Haha' const buffer = Buffer.from(msg, 'utf-8') console.log(buffer.toString('utf16le')); //
2. The image file
copies the image encoding to achieve the purpose of copying the image.
encoding
attribute, because the character encoding is only read when reading the image. It is only useful when fetching text files.const fs = require('fs') fs.readFile('./logo.png', (err, data) => { console.log(data); // What is printed is the binary encoding corresponding to the image file // We can also write the image encoding to another file, which is equivalent to us copying the image fs.writeFile(' ./bar.png', data, err => { console.log(err); }) })
sharp
libraryconst sharp = require('sharp') // Crop the logo.png image to 200x300 and copy it to the file bax.png sharp('./logo.png') .resize(200, 300) .toFile('./bax.png', (err, info) => { console.log(err); }) // You can also convert the image file into a buffer first, and then write it to the file. You can also copy the image sharp('./logo.png') .resize(300, 300) .toBuffer() .then(data => { fs.writeFile('./baa.png', data, err => { console.log(err); }) })
Buffer creation process
Buffer
, we will not frequently apply for memory from the operating system. By default, it will first apply for a memory of 8 * 1024
bytes, that is, 8kb
What is an event loop?
What is the event loop?
JS
we write and the browser or Node
.JS
code we write and the browser API calls ( setTimeout
, AJAX
,监听事件
, etc.) Bridges communicate through callback functions.file system
, networ
, etc.). Bridges also communicate through callback functions.Process and thread
Process and thread are two concepts in the operating system:
process
): the program that the computer has runthread
): the smallest unit that the operating system can run the calculation schedule, so CPU
can directly operate the thread, whichsounds very abstract. , let’s explain it intuitively:
Let's use a vivid example to explain
multi-process multi-thread development
operating system. How can multiple processes (while listening to music, writing code, and checking information) work at the same time?
CPU
's computing speed is very fast, and it can quickly switch between multiple processes.Browsers and JavaScript
We often say that JavaScript
is single-threaded, but the JS thread should have its own container process Node
Is the browser or Node browser a process? Is there only one thread in it?
tab
page, a new process will be started. This is to prevent one page from getting stuck and causing all pages to become unresponsive. The entire browser needs to be forced to exitHowever, JavaScript code execution is executed in a separate thread.
JS
code can only do one thing at the same time.JavaScript execution process
function will not be executed until it is pushed into the function call stack. Let's analyze the execution process of the code
const message = 'Hello World ' console.log(message); function sum(num1, num2) { return num1 + num2 } function foo() { const result = sum(20, 30) console.log(result); } foo()
main
function like other programming languagesmessage
log
function. The log function will be placed Enter the function call stack. After execution, pop the stackfoo
function. The foo function is pushed into the function call stack. However, the sum
function needs to be called during execution,js
code is executed, and the main function is popped out ofthe browser's event loop
. What if there are asynchronous operations during the execution of the JS
code?
setTimeout
function call in the middleThen, the function passed into the setTimeout function (we call it timer
function), when will it be executed?
web api
. The browser will store the callback function in advance. At the appropriate time, the timer function will be added to an event queue.Why does setTimeout not block the execution of the code
It is because the browser maintains a very, very important thing - the event loop
browser will help us save the callback function in setTimeout in some way. The more common method is to save it in a red-black tree
and wait until setTimeout is scheduled. When the timer time arrives, it will take our timer callback function out of the saved place and put it into the event queue.
Once the event loop finds that there is something in our queue, and the current function call stack is empty, other After the synchronization code is executed, the callback functions in our queue will be dequeued and put into the function call stack for execution (the next function will not be pushed into the stack until the previous function in the queue is popped out).
Of course, there are no There must be only one event. For example, during a certain process, the user clicks a button in the browser. We may have a monitor for the click of this button, which corresponds to a callback function. That callback function will also be added to our In the queue, the execution order is based on the order they are in the event queue. There is also a summary of the callbacks we send ajax
requests to the event queue
: In fact, the event loop is a very simple thing. It means that when a certain callback needs to be executed under a special situation, it will The callback saved in advance is stuffed into the event queue, and the event loop takes it out and puts it into the function call stack.
Macro tasks and micro tasks.
However, the event loop does not maintain only one queue. In fact, there are two queues, and the execution of tasks in the queue must wait
macrotask queue
ajax
setTimeout
, setInterval
, DOM
monitoring, UI Rendering
and othermicrotask queue
): Promise
's then
callback, Mutation Observer API
, queueMicrotask()
, etc.So what is the priority of the two queues in the event loop?
main script
is executed first (the top-level script code written).questions <1>
Test points: main stcipt
, setTimeout
, Promise
, then
, queueMicrotask
setTimeout(() => { console.log('set1');4 new Promise(resolve => { resolve() }).then(resolve => { new Promise(resolve => { resolve() }).then(() => { console.log('then4'); }) console.log('then2'); }) }) new Promise(resolve => { console.log('pr1'); resolve() }).then(() => { console.log('then1'); }) setTimeout(() => { console.log('set2'); }) console.log(2); queueMicrotask(() => { console.log('queueMicrotask'); }) new Promise(resolve => { resolve() }).then(() => { console.log('then3'); }) // pr1 // 2 //then1 //queueMicrotask //then3 // set1 //then2 //then4 // set2
setTimeout
will be pushed into the function call stack immediately, and will be popped out of the stack immediately after execution. Its timer
function will be put into the macro task queue.
The function passed into the Promise
class will be executed immediately. It is not a callback function, so it will be printed. pr1
comes out, and because the resolve
method is executed, the status of the Promise will immediately change to fulfilled
, so that when the then
function is executed, its corresponding callback function will be put into the microtask queue and
a setTimeout function is encountered again. When the stack is popped, its timer function will be put into the macro task queue
when it encounters console.log
statement. After the function is pushed onto the stack, 2
is printed out, and then popped out.
A function is bound to queueMicrotask
here, and the function will be placed After entering the microtask queue,
a new Promise statement was encountered, but it immediately changed the promise status to fulfilled, so the callback corresponding to the then function was also put into the microtask queue.
Since the synchronization script code has been executed, now the event At the beginning of the loop, the tasks competing against the micro-task queue and the macro-task are put into the function call stack in order of priority. Note: The priority of micro-tasks is higher than that of macro-tasks. You must read it every time before you want to execute a macro-task. Check whether the microtask queue is empty. If it is not empty, you need to execute the task of the microtask queue first.
The first microtask is to print then1
, the second microtask is to print queueMicrotask, and the third microtask is to print then3
. The execution is completed. After that, start executing the macro task.
The first macro task is more complicated. It will first print set1
, and then execute a new promise
statement that immediately changes the state. Its then callback will be put into the microtask queue. Note that the microtask is now The queue is not empty, so a microtask queue with a higher priority needs to be executed, which is equivalent to the then callback being executed immediately. It is the same new Promise statement, and its corresponding then swap is put into the microtask queue. Note that there is a console
function after the new Promise statement. This function will be executed immediately after the new Promise statement is executed, that is, printing then2
. There is still a task in the microtask confrontation, so the next step is to print then4
. So far, the microtask queue is empty, and the macrotask queue can continue to be executed
, so the next macrotask set2
will be printed. After the macrotask is executed,
the printing result of the entire code is: pr1 -> 2 -> then1 -> queueMicrotask -> then3 -> set1 -> then2 -> then4 -> set2
Interview questions <2>
Test points: main script
, setTimeout
, Promise
, then
, queueMicrotask
, await
, async
knowledge supplement: async, await is a syntax sugar for Promise
. When dealing with event loop issues,
new Promise((resolve,rejcet) => { 函数执行})
then(res => {函数执行})
in the previous Promiseasync function async1() { console.log('async1 start'); await async2() console.log('async1 end'); } async function async2() { console.log('async2'); } console.log('script start'); setTimeout(() => { console.log('setTimeout'); }, 0) async1() new Promise(resolve => { console.log('promise1'); resolve() }).then(() => { console.log('promise2'); }) console.log('script end'); // script start // async1 start // async2 // promise1 // script end // async1 end // promise2 // setTimeout
is a function definition at the beginning, and does not need to be pushed into the function call stack for execution until it encounters the first console
statement. After pushing the stack, execute the print script start
and then pop it out of the stack
to encounter the first setTimeout
function, which corresponds to timer
will be put into the macro task queue
and the async1 function will be executed. First, async1 start
will be printed, and then the async2
function after await
statement will be executed. Because as mentioned before, the function after the await keyword is regarded as new Promise
The statement in new Promise
, this function will be executed immediately, so async2 will be printed out, but the code after the await statement is equivalent to being put into the then callback, that is to say, console.log('async1 end')
This line of code is put into the microtask queue
and the code continues to execute. It encounters a new Promise statement, so promise1
is immediately printed. The function in the then callback is put into the microtask queue to
execute the last console function for printing. script end
, the synchronization code has been executed. The event loop will go to the macro task and micro task queues to execute tasks.
First, go to the micro task queue. The print statement corresponding to the first micro task will be executed, which means async1 end
will be printed, and then promise2
is printed. At this time, the microtask queue is empty, and the tasks in the macrotask queue are started to be executed.
The setTimeout corresponding to the timer function will be printed. At this time, the macrotask is also executed, and the final printing sequence is It is: script start -> async1 start -> async2 -> promise1 -> script end -> async1 end -> promise2 -> setTimeout