
двоичные данные
Весь контент на компьютере: текст, числа, изображения, аудио и видео в конечном итоге будет представлен в двоичном виде.
JS может напрямую обрабатывать очень интуитивные данные: например, строки. Обычно мы показываем это содержимое пользователям,
но вы можете подумать, что это JS. Также может обрабатывать изображения.
JS или HTML . Он отвечает только за сообщение браузеру адреса изображения.Однако для сервера все по-другому.
utf-8 , а с помощью GBK . мы должны прочитать их. Двоичные данные затем преобразуются в соответствующий текст через GKB.sharp , которая отвечает за чтение картинок или Buffer входящих картинок и их последующую обработку.Node устанавливается длинное соединение через TCP , передающее байт. поток Нам нужно Данные преобразуются в байты перед передачей, и размер передаваемых байтов должен быть известен (клиент должен судить, какой объем контента нужно прочитать, исходя из размера).Буферный и двоичный.
Мы обнаружим это. для внешней разработки это обычно редко связано с двоичным взаимодействием друг с другом, но для серверной стороны, чтобы реализовать множество функций, мы должны напрямую управлять его двоичными данными.
Поэтому, чтобы облегчить разработчикам выполнение большего количества функций
Node предоставляет нам класс с именем Buffer , и он является глобальным. Как
мы уже говорили, двоичные данные хранятся в Buffer, так как же они хранятся?
8 -битный двоичный код: 00000000 , что составляет ровно один байт. Почему он 8-битный?
byte1 byte = 8 bit1 byte = 8 bit , 1kb = 1024 byte , 1M = 1024kb , 1 G = 1024 Mint во многих языках программирования составляет 4 байта, а тип long — 8 байт.TCP передаетRGB равны 255 соответственно, поэтому по сутиBuffer и строковый
Buffer хранятся в компьютере одним байтом, что составляет эквивалент массива байтов. Каждый элемент массива имеет размер одного байта.
Если мы хотим поместить строку в буфер, каков процесс?
buffer .const message = 'Hello'. // Используйте ключевое слово new для создания экземпляра буфера, но срок действия этого метода создания истек const buffer = new Buffer(message) console.log(buffer); // <Буфер 48 65 6c 6c 6f> console.log(buffer.toString()); // Привет,
кодировка и декодирование строк на китайском языке.
buffer по умолчанию — utf-8 , поэтому в следующем коде класс Buffer использует кодировку utf-8 для кодирования нашей строки. мы также используем utf-8 для декодирования наших строк.3 байтовому двоичному сообщениюconst = «Hello». // Используем Buffer.from для декодирования нашей строки const buffer = Buffer.from(message) console.log(buffer); // <Буфер e4 bd a0 e5 a5 bd e5 95 8a> // В экземпляре буфера есть метод toString, который может декодировать кодировку console.log(buffer.toString()); // 'Здравствуйте'
, что произойдет, если кодирование и декодирование используют разные формы результатов кодирования?
const message = 'Hello' const buffer = Buffer.from(сообщение, 'utf16le') console.log(buffer); // <Буфер 60 4f 7d 59 4a 55> console.log(buffer.toString()); // `O}YJU
Другие способы создания буферов
buffer Здесь мы можем создавать Buffer с помощью alloc
Мы можем напрямую создавать экземпляры буферов в виде массивов. каждый бит изменяется.
// которое может указать количество цифр в нашем буфере. Например, если здесь передано 8, то созданный буфер будет содержать 8 элементов, а двоичное число, соответствующее каждому элементу, будет равно 0. константный буфер = Buffer.alloc(8) console.log(buffer); // <Буфер 00 00 00 00 00 00 00 00> // Если значению присвоено десятичное число, буфер поможет нам преобразовать его в шестнадцатеричное число, а затем записать в соответствующее место buffer[0] = 88 // В js все, что начинается с 0x, представлено как шестнадцатеричное число buffer[1] = 0x88 console.log(buffer); // <Buffer 58 88 00 00 00 00 00 00>
Операции с буфером и файлом
1. Если в текстовом файле
buffer . , который является результатом двоичного числа в кодировке utf-8const fs = require('fs')
fs.readFile('./a.txt', (ошибка, данные) => {
console.log(данные); // <Буфер e5 93 88 e5 93 88>
}) const fs = require('fs')
// кодировка указывает кодировку символов, используемую для декодирования, по умолчанию используется кодировка utf-8
fs.readFile('./a.txt', { кодировка: 'utf-8' }, (ошибка, данные) => {
console.log(data); // Ха-ха}) const fs = require('fs')
// В кодировке используется кодировка символов utf16le, а в декодировании используется формат utf-8. Должно быть, декодирование неправильное. fs.readFile('./a.txt', {coding: 'utf16le' }, (err. , данные) => {
console.log(данные); // Ошибка })
// Приведенный выше код аналогичен следующему коду const msg = 'Ха-ха'
const buffer = Buffer.from(msg, 'utf-8')
console.log(buffer.toString('utf16le')); // 2. Файл изображения
копирует кодировку изображения для достижения цели копирования изображения.
encoding , поскольку кодировка символов. читается только при чтении изображения. Это полезно только при получении текстовых файлов.const fs = require('fs').
fs.readFile('./logo.png', (ошибка, данные) => {
console.log(data); // Выводится двоичная кодировка, соответствующая файлу изображения // Мы также можем записать кодировку изображения в другой файл, что эквивалентно копированию изображения fs.writeFile(' ./bar .png', данные, ошибка => {
console.log(ошибка);
})
}) sharpconst Sharp = require('sharp')
// Обрезаем изображение logo.png до размера 200x300 и копируем его в файл bax.png Sharp('./logo.png')
.resize(200, 300)
.toFile('./bax.png', (ошибка, информация) => {
console.log(ошибка);
})
// Вы также можете сначала преобразовать файл изображения в буфер, а затем записать его в файл. Вы также можете скопировать изображение Sharp('./logo.png')
.resize(300, 300)
.toBuffer()
.then(данные => {
fs.writeFile('./baa.png', данные, ошибка => {
console.log(ошибка);
})
}) Процесс создания буфера
Buffer , мы не будем часто обращаться к памяти из операционной системы. По умолчанию он сначала будет обращаться к памяти размером 8 * 1024 байт, то есть 8kb ,Что такое цикл событий?
Что такое цикл событий?
JS который мы пишем, и браузером или Node .JS который мы пишем, и вызовами API браузера ( setTimeout , AJAX ,监听事件и т. д.). ) Мосты взаимодействуют через функции обратного вызова.file system , networ и т. д.). Мосты также взаимодействуют через функции обратного вызова.
Процесс и поток
Процесс и поток — это две концепции в операционной системе:
process ): программа, которую компьютер запускаетthread ): наименьшая единица, с которой операционная система может запускать расписание вычислений, поэтому CPU может работать напрямую. поток, которыйзвучит очень абстрактно, давайте объясним это интуитивно:
Давайте на ярком примере объясним
многопроцессная многопоточная
операционная система.Как можно выполнять несколько процессов (при прослушивании музыки, написании кода). , и проверка информации) работают одновременно?

CPU очень высока и он может быстро переключаться между несколькими процессами.
Браузеры и JavaScript
Мы часто говорим, что JavaScript является однопоточным, но поток JS должен иметь собственный процесс-контейнер Node
Является ли браузер или браузер Node процессом?
tab , запускается новый процесс. Это необходимо для предотвращения зависания одной страницы и зависания всех страниц. Необходимо принудительно закрытьОднако выполнение кода JavaScript выполняется в отдельном потоке.
JS .процесса выполнения JavaScript
не будет выполнена, пока она не будет помещена в стек вызовов функций. Давайте проанализируем процесс выполнения кода
const message = 'Hello World'.
console.log(сообщение);
функция сумма (число1, число2) {
вернуть число1 + число2
}
функция Фу() {
константный результат = сумма (20, 30)
console.log(результат);
}
foo() main функции, как и в других языках программированияmessagelog . Функция будет помещена. Введите стек вызовов функций. После выполнения извлеките стекfoo . Функция foo помещается в стек вызовов функций. Однако функцию sum необходимо вызвать во время выполнения,js код, а основная функция выскакивает изцикла событий браузера
. Что делать, если во время выполнения JS кода происходят асинхронные операции?
setTimeout в серединеЗатем функция передается в функцию setTimeout
.(мы называем это функцией timer ), когда она будет выполнена?
web api . Браузер заранее сохранит функцию обратного вызова. В подходящее время функция таймера будет добавлена в очередь событий.Почему setTimeout не блокирует выполнение кода,
Это потому, что браузер поддерживает очень, очень важную вещь —
браузер цикла событий поможет нам каким-то образом сохранить функцию обратного вызова в setTimeout. Более распространенный метод — сохранить ее в красно-черном дереве
и дождаться запланированного setTimeout. Когда наступит время таймера, наша функция обратного вызова таймера будет удалена из сохраненного места и помещена в очередь событий.
Как только цикл событий обнаружит, что в нашей очереди что-то есть, а текущий стек вызовов функции пуст, другое.
синхронизации
функции обратного вызова в нашей очереди будут исключены из очереди и помещены в стек вызовов функций для выполнения (следующая функция не будет помещена в стек до тех пор, пока не выйдет предыдущая функция в очереди).
, нет. Должно быть только одно событие. Например, во время определенного процесса пользователь нажимает кнопку в браузере. У нас может быть монитор нажатия этой кнопки, который соответствует этой функции обратного вызова. также будут добавлены в нашу очередь. Порядок выполнения зависит от порядка их расположения в очереди событий. Существует также сводка обратных вызовов, которые мы отправляем ajax запросы в очередь событий
: На самом деле цикл событий — это очень простая вещь. Это означает, что когда определенный обратный вызов должен быть выполнен в особой ситуации, он будет сохранен. заранее помещается в очередь событий, а цикл событий извлекает его и помещает в стек вызовов функций.

Макрозадачи и микрозадачи.
Однако цикл событий не поддерживает только одну очередь. На самом деле очередей две, и выполнение задач в очереди должно ждать,
macrotask queueajaxsetTimeout , setInterval , мониторинг DOM , UI Rendering и другиеmicrotask queue ): then вызов Promise , Mutation Observer API , queueMicrotask() и т. д.Итак, каков приоритет двух очередей в цикле событий?
main script выполняется первым (написан код скрипта верхнего уровня)..
Тестовые точки: main stcipt , setTimeout , Promise , then , queueMicrotask
setTimeout(() => {
console.log('set1');4
новое обещание (решить => {
решать()
}).then(решить => {
новое обещание (решить => {
решать()
}).then(() => {
console.log('then4');
})
console.log('then2');
})
})
новое обещание (решить => {
console.log('pr1');
решать()
}).then(() => {
console.log('then1');
})
setTimeout(() => {
console.log('set2');
})
консоль.журнал(2);
очередьМикротаск(() => {
console.log('queueMicrotask');
})
новое обещание (решить => {
решать()
}).then(() => {
console.log('then3');
})
// пр1
// 2
//тогда1
//очередьМикрозадача
//тогда3
// набор1
//тогда2
//тогда4
// set2 setTimeout будет немедленно помещен в стек вызова функции и будет извлечен из стека сразу после выполнения. Его функция timer будет помещена в очередь задач макроса.
Функция, переданная в класс Promise , будет выполнена немедленно. Это не функция обратного вызова, поэтому будет напечатан pr1 , и поскольку метод resolve будет выполнен, статус Promise немедленно изменится на fulfilled , так что при выполнении функции then будет выполнена соответствующая функция обратного вызова. быть помещен в очередь микрозадач
, и функция setTimeout встречается снова. При извлечении стека ее функция таймера будет помещена в очередь макрозадач
, когда она встретит оператор console.log . После того, как функция будет помещена в стек, 2 распечатывается, а затем выскакивает.
Здесь функция привязана к queueMicrotask , и функция будет помещена. После входа в очередь микрозадач
был обнаружен новый оператор Promise, но он сразу же изменил статус обещания на выполненное, поэтому обратный вызов соответствующая функции then также была помещена в очередь микрозадач.
Поскольку код сценария синхронизации был выполнен, теперь событие В начале цикла задачи, конкурирующие с очередью микрозадач, и макрозадача помещаются в очередь. стек вызовов функций в порядке приоритета. Примечание. Приоритет микрозадач выше, чем у макрозадач. Вы должны читать его каждый раз, прежде чем выполнять макрозадачу. Проверьте, пуста ли очередь микрозадач. он не пуст, вам нужно сначала выполнить задачу очереди микрозадач.
Первая микрозадача — напечатать then1 , вторая микрозадача — напечататьqueueMicrotask, а третья микрозадача — напечатать then3 . После этого выполнение завершается. начать выполнение макрозадачи.
Первая макрозадача более сложная. Сначала она выведет set1 , а затем выполнит new promise , который немедленно изменит состояние. Затем обратный вызов будет помещен в очередь микрозадач. Очередь не пуста, поэтому необходимо выполнить очередь микрозадач с более высоким приоритетом, что эквивалентно немедленному выполнению обратного вызова then. Это тот же новый оператор Promise, и соответствующий ему обмен then помещается в очередь микрозадач. Обратите внимание, что после нового оператора Promise есть console функция. Эта функция будет выполнена сразу после выполнения нового оператора Promise, то есть вывода then2 . В сопоставлении микрозадач все еще есть задача, поэтому следующим шагом будет печать. then4 . На данный момент очередь микрозадач пуста, и очередь макрозадач может продолжать выполняться
, поэтому будет напечатан следующий set2 макрозадач2. После выполнения макрозадачи
результат печати всего кода: pr1 -> 2 -> then1 -> queueMicrotask -> then3 -> set1 -> then2 -> then4 -> set2
Вопросы для собеседования <2>
Тестовые точки: main script , setTimeout , Promise , then , queueMicrotask , await async
дополнение к асинхронным знаниям: async, await — это синтаксический сахар for Promise . При возникновении проблем с циклом событий
new Promise((resolve,rejcet) => { 函数执行})then(res => {函数执行}) в предыдущем Promiseasync function async1() {
console.log('async1 start');
дождитесь асинхронного2()
console.log('конец async1');
}
асинхронная функция async2() {
console.log('async2');
}
console.log('запуск скрипта');
setTimeout(() => {
console.log('setTimeout');
}, 0)
асинхронный1()
новое обещание (решить => {
console.log('обещание1');
решать()
}).then(() => {
console.log('обещание2');
})
console.log('конец сценария');
// запуск скрипта
// начало асинхронного1
// асинхронный2
// обещание1
// конец скрипта
// конец асинхронного1
// обещание2
// setTimeout — это определение функции в начале, и его не нужно помещать в стек вызовов функций для выполнения до тех пор, пока он не встретит первый оператор console . После помещения стека выполните script start печати, а затем извлеките его из стека. стек
для обнаружения первой функции setTimeout , которая соответствует timer будет помещен в очередь задач макроса
, и будет выполнена функция async1. Сначала будет напечатан async1 start , а затем будет выполнена функция async2 после оператора await . Поскольку, как упоминалось ранее, функция после ключевого слова await считается new Promise , эта функция будет выполнена немедленно, поэтому будет распечатан async2, но код после оператора await эквивалентен помещению в then. обратный вызов, то есть console.log('async1 end') Эта строка кода помещается в очередь микрозадач
, и код продолжает выполняться. Он встречает новый оператор Promise, поэтому функция promise1 немедленно выводится. затем обратный вызов помещается в очередь микрозадач для
выполнения последней консольной функции для script end , код синхронизации будет выполнен. Цикл событий перейдет к очередям макро-задач и микро-задач для выполнения задач
. Очередь задач будет выполнена, что означает, что будет напечатан async1 end , а затем напечатано promise2 . В это время очередь микрозадач пуста, и начинаются задачи в очереди макрозадач. быть выполнено.
Будет напечатано значение setTimeout, соответствующее функции таймера. В это время также выполняется макрозадача, и окончательная последовательность печати: script start -> async1 start -> async2 -> promise1 -> script end -> async1 end -> promise2 -> setTimeout