데이터 바이너리
컴퓨터에 있는 모든 콘텐츠(텍스트, 숫자, 그림, 오디오, 비디오)는 결국 바이너리로 표시됩니다.
JS
문자열과 같은 매우 직관적인 데이터를 직접 처리할 수 있지만 일반적으로 이러한 콘텐츠를 사용자에게 표시하는
것은 JS입니다.
실제로 웹 페이지에서이미지
JS
또는 HTML
에 의해 브라우저에 처리되었습니다. 브라우저는 이미지를그러나 서버에서는
utf-8
로 인코딩되지 않고 GBK
로 인코딩됩니다Buffer
읽고 처리하는 sharp
가 있습니다.Node
에서는 TCP
통해 바이트를 전송합니다. 데이터는 전달되기 전에 바이트로 변환되어야 하며 전송된 바이트의 크기를 알아야 합니다(클라이언트는 크기에 따라 읽을 콘텐츠의 양을 판단해야 함)
. 프런트엔드 개발의 경우 일반적으로 바이너리와 관련이 거의 없지만 서버 측의 경우 많은 기능을 구현하려면 바이너리 데이터를 직접 조작해야
개발자가 더 많은 기능을 완료할 수 있습니다
, Node
Buffer
라는 클래스를 제공하며 이는 전역적입니다.
앞서 말했듯이 바이너리 데이터는 Buffer에 저장되는데 어떻게 저장됩니까?
8
비트 바이너리인 00000000
저장할 수 있습니다. 이는 정확히 1바이트입니다.
1 byte = 8 bit
byte
라고 합니다.1 byte = 8 bit
, 1kb = 1024 byte
, 1M = 1024kb
, 1 G = 1024 M
int
유형은 4
바이트이고, long
유형은 8
바이트입니다.TCP
For를 전송합니다RGB
값은 각각 255
이므로 본질적으로Buffer와 문자열
Buffer
컴퓨터에 1바이트로 저장됩니다. 바이트 배열과 같습니다. 배열의 각 항목 크기는 1바이트입니다.
문자열을 버퍼에 넣으려면 어떻게 해야 합니까?
const message = 'Hello'
buffer
// new 키워드를 사용하여 버퍼 인스턴스를 생성했지만 이 생성 방법은 만료되었습니다. const buffer = new Buffer(message) console.log(버퍼); // <버퍼 48 65 6c 6c 6f> console.log(buffer.toString()); // Hello
Chinese 문자열 인코딩 및 디코딩.
buffer
의 기본 인코딩은 utf-8
이므로 다음 코드에서 Buffer
클래스는 문자열을 인코딩하기 위해 utf-8 인코딩을 사용합니다. , 우리는 또한 문자열을 디코딩하기 위해 utf-8을 사용합니다.3
바이트 바이너리 인코딩에 해당합니다.const message = 'Hello' // Buffer.from을 사용하여 문자열을 디코딩합니다. const buffer = Buffer.from(message) console.log(버퍼); // <버퍼 e4 bd a0 e5 a5 bd e5 95 8a> // 버퍼 인스턴스에 인코딩을 디코딩할 수 있는 toString 메서드가 있습니다. console.log(buffer.toString()); // 'Hello'
, 인코딩과 디코딩이 서로 다른 형태의 인코딩 결과를 사용하면 어떻게 될까요?
const message = 'Hello' const 버퍼 = Buffer.from(메시지, 'utf16le') console.log(버퍼); // <버퍼 60 4f 7d 59 4a 55> console.log(buffer.toString()); // `O}YJU
버퍼를 생성하는 다른 방법은
buffer
합니다. Buffer
alloc
을 통해 버퍼 인스턴스를 직접 생성할 수 있습니다
// 자릿수를 지정할 수 있도록
직접
예를 들어 여기에 8이 전달되면 생성된 버퍼에는 8개의 요소가 있고 각 요소에 해당하는 이진수는 0입니다. const 버퍼 = Buffer.alloc(8) console.log(버퍼); // <버퍼 00 00 00 00 00 00 00 00> // 값이 10진수에 할당되면 버퍼는 이를 16진수로 변환한 다음 해당 위치에 쓰는 데 도움이 됩니다. buffer[0] = 88 // js에서는 0x로 시작하는 모든 것이 16진수로 표시됩니다. buffer[1] = 0x88 console.log(buffer); // <Buffer 58 88 00 00 00 00 00 00>
버퍼 및 파일 작업
1. 텍스트 파일에
buffer
직접 반환됩니다. 이는 파일 내용 결과입니다. utf-8
로 인코딩된 이진수const fs = require('fs') fs.readFile('./a.txt', (err, data) => { console.log(data); // <버퍼 e5 93 88 e5 93 88> })인코딩 및 디코딩은 utf-8을 사용하므로
const fs = require('fs')
// 인코딩은 디코딩에 사용되는 문자 인코딩을 나타내며 인코딩의 기본값은 utf-8입니다. fs.readFile('./a.txt', { 인코딩: 'utf-8' }, (err, data) => { console.log(data); // ㅎㅎ})
const fs = require('fs') // 인코딩은 utf16le 문자 인코딩을 사용하고, 디코딩은 utf-8 형식을 사용합니다. fs.readFile('./a.txt', { 인코딩: 'utf16le' }, (err) , 데이터) => { console.log(data); // 오류 }) // 위 코드는 다음 코드와 유사합니다. const msg = '하하' const 버퍼 = Buffer.from(msg, 'utf-8') console.log(buffer.toString('utf16le')); //
2. 이미지 파일은
이미지 복사 목적을 달성하기 위해 이미지 인코딩을 복사합니다
encoding
이미지를 읽을 때만 읽습니다.const fs = require('fs') fs.readFile('./logo.png', (err, 데이터) => { console.log(data); // 인쇄되는 것은 이미지 파일에 해당하는 바이너리 인코딩입니다. // 이미지 인코딩을 다른 파일에 쓸 수도 있습니다. 이는 이미지를 복사하는 것과 같습니다. fs.writeFile(' ./bar .png', 데이터, 오류 => { console.log(err); }) })
sharp
라이브러리를 사용할 수 있습니다.const Sharp = require('sharp') // logo.png 이미지를 200x300으로 자르고 bax.png 파일에 복사합니다. Sharp('./logo.png') .크기 조정(200, 300) .toFile('./bax.png', (err, info) => { console.log(err); }) // 이미지 파일을 먼저 버퍼로 변환한 후 파일에 쓸 수도 있습니다. Sharp('./logo.png') .크기 조정(300, 300) .toBuffer() .then(데이터 => { fs.writeFile('./baa.png', 데이터, 오류 => { console.log(err); }) })
버퍼 생성 과정
Buffer
생성할 때 운영체제에서 메모리를 자주 적용하지는 않을 것이다. 8 * 1024
8kb
이벤트 루프란 무엇입니까?
이벤트 루프란 무엇입니까?
JS
와 브라우저 또는 Node
사이의 브리지로 이해합니다.JS
코드와 브라우저 API 호출( setTimeout
, AJAX
,监听事件
등) 사이의 링크입니다. ) 브리지는 콜백 함수를 통해 통신합니다.file system
, networ
등) 사이의 브리지이기도 합니다.프로세스와 스레드
프로세스와 스레드는 운영 체제에서 두 가지 개념입니다.
process
) : 컴퓨터가 실행한 프로그램thread
) : 운영 체제가 실행할 수 있는 가장 작은 단위 계산 일정, CPU
직접 작동할 수 있음직관적으로 설명하겠습니다.
.
다중 프로세스 다중 스레드 개발
운영 체제입니다. , 정보 확인)이 동시에 작동합니까?
CPU
의 컴퓨팅 속도가 매우 빠르고 여러 프로세스 사이를 빠르게 전환할 수 있기 때문입니다.브라우저와 JavaScript
우리는 종종 JavaScript
가 단일 스레드라고 말하지만 JS 스레드에는 자체 컨테이너 프로세스가 있어야 합니다 Node
브라우저 또는 노드 브라우저가 프로세스입니까?
tab
페이지를 열면 새 프로세스가 시작됩니다. 이는 한 페이지가 중단되어 모든 페이지가그러나 JavaScript 코드 실행은 별도의 스레드에서 실행됩니다.
JS
코드가 동시에 한 가지 작업만 수행할 수 있다는 것을 의미합니다JavaScript 실행 프로세스
함수는 함수 호출 스택에 푸시될 때까지 실행되지 않습니다.const message = 'Hello World'
코드의 실행 프로세스를 분석해 보겠습니다.
console.log(메시지); 함수 합계(숫자1, 숫자2) { 숫자1 + 숫자2를 반환합니다. } 함수 foo() { const 결과 = 합계(20, 30) console.log(결과); } foo()
main
함수에서 실행되는 것으로 간주할 수 있습니다message
변수를 정의한log
함수를 실행해야 합니다. 함수 호출 스택에 들어갑니다. 실행 후 스택을 팝foo
함수를 호출합니다. 그러나 sum
함수는 실행 중에 호출되어야 하므로브라우저의 이벤트 루프
js
빠져나옵니다. JS
코드 실행 중에 비동기 작업이 발생하면 어떻게 될까요?
setTimeout
함수 호출을 삽입하면그러면 함수가 setTimeout 함수에 전달됩니다. (우리는 이것을 timer
함수라고 부릅니다.) 언제 실행될까요?
web api
호출합니다. 적절한 시점에 타이머 함수가 이벤트 대기열에 추가됩니다코드 실행을 차단하지 않는 이유는 무엇입니까
?브라우저가 매우 중요한 것을 유지하기 때문입니다. 이벤트 루프
브라우저는 어떤 방식으로든 콜백 함수를 setTimeout에 저장하는 데 도움이 됩니다. 더 일반적인 방법은 이를 레드-블랙 트리에 저장
하고 setTimeout이 예약될 때까지 기다리는 것
타이머 시간이 되면 타이머 콜백 함수를 저장된 위치에서 꺼내 이벤트 큐에 넣습니다.
이벤트 루프가 큐에 무언가가 있고 현재 함수 호출 스택이 비어 있음을 발견하면 다른 동기화 코드가 실행된 후 대기열의 콜백 함수는 대기열에서 제외되고 실행을 위해 함수 호출 스택에 배치됩니다(
물론
대기열의 이전 함수가 팝업될 때까지 다음 함수는 스택에 푸시되지 않습니다).예를 들어, 특정 프로세스 중에 사용자가 브라우저에서 버튼을 클릭하면 콜백 함수에 해당하는 이 버튼의 클릭에 대한 모니터가 있을 수 있습니다. In the queue에도 추가됩니다. 실행 순서는 이벤트 대기열에 있는 순서를 기반으로 합니다. 이벤트 큐에 ajax
요청을 보내는 콜백에 대한 요약도 있습니다
. 사실 이벤트 루프는 매우 간단합니다. 이는 특정 콜백이 특별한 상황에서 실행되어야 할 때 콜백이 저장된다는 것을 의미합니다. 미리 이벤트 큐에 채워지고, 이벤트 루프는 이를 꺼내서 함수 호출 스택에 넣습니다.
매크로 태스크와 마이크로 태스크
macrotask queue
이벤트 루프는 큐가 하나만 유지되지 않으며 큐에 있는 태스크의 실행은 모든 스크립트가 실행될
ajax
setTimeout
, setInterval
, DOM
모니터링, UI Rendering
및 기타microtask queue
): Promise
의 then
, Mutation Observer API
, queueMicrotask()
등.그렇다면 이벤트 루프에 있는 두 대기열의 우선순위는 무엇입니까?
main script
의 코드가 먼저 실행됩니다(작성된 최상위 스크립트 코드).질문 <1>
에 있는 작업(콜백)이 먼저 실행됩니다.테스트 포인트: 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'); }) console.log(2); queueMicrotask(() => { console.log('queueMicrotask'); }) 새로운 약속(해결 => { 해결하다() }).then(() => { console.log('then3'); }) //pr1 // 2 //다음1 //queue마이크로태스크 //다음3 // 세트1 //다음2 //다음4 // set2
setTimeout
즉시 함수 호출 스택에 푸시되고 실행 후 즉시 스택에서 제거됩니다. 해당 timer
함수는
Promise
클래스에 전달된 함수가 즉시 실행됩니다. 콜백 함수가 아니기 때문에 pr1
나오며, resolve
메소드가 실행되기 때문에 Promise 상태가 즉시 fulfilled
로 변경되므로 then
함수가 실행되면 해당 콜백 함수가 실행됩니다. 마이크로태스크 대기열에 들어가고
함수가 스택에 푸시 console.log
2
해당 타이머 함수가 매크로 작업 대기열에 배치됩니다
여기에 함수가 queueMicrotask
에 바인딩되어 있고 함수가 배치됩니다
.
새로운 Promise 문이 발생했지만 Promise 상태가 즉시 이행으로 변경되었으므로 콜백이 실행됩니다. then 함수에 해당하는 작업도 마이크로태스크 큐에 들어갔습니다.
동기화 스크립트 코드가 실행되었으므로 이제 이벤트 루프 시작 시 마이크로태스크 큐 및 매크로태스크와 경쟁하는 작업이 들어갑니다. 참고: 마이크로 태스크의 우선순위는 매크로 태스크의 우선순위보다 높습니다. 매크로 태스크를 실행하기 전에 항상 읽어야 합니다. 비어 있지 않으면 먼저 마이크로태스크 대기열의 작업을 실행해야 합니다.
첫 번째 마이크로태스크는 then1
인쇄하고, 두 번째 마이크로태스크는 queueMicrotask 를 인쇄하고, 세 번째 마이크로태스크는 then3
인쇄하는 것입니다. 매크로 작업 실행을 시작합니다.
첫 번째 매크로 작업은 먼저 set1
인쇄한 다음 즉시 상태를 변경하는 new promise
문을 실행합니다. 이제 마이크로 작업 대기열에 들어갑니다. 대기열은 비어 있지 않으므로 우선순위가 더 높은 마이크로태스크 대기열을 실행해야 하며 이는 즉시 실행되는 then 콜백과 동일합니다. 이는 동일한 새 Promise 문이며 해당 then 스왑이 마이크로태스크 대기열에 배치됩니다. 새 Promise 문 뒤에는 console
기능이 있습니다. 이 함수는 새 Promise 문이 실행된 직후에 실행됩니다. 즉, then2
인쇄하는 작업이 아직 남아 있으므로 다음 단계는 인쇄하는 것입니다. then4
. 지금까지는 마이크로태스크 대기열이 비어 있고 매크로태스크 대기열이 계속 실행될 수 있으므로
다음 매크로태스크 set2
인쇄됩니다. 매크로태스크가 실행된 후
전체 코드의 인쇄 결과는 pr1 -> 2 -> then1 -> queueMicrotask -> then3 -> set1 -> then2 -> then4 -> set2
입니다. pr1 -> 2 -> then1 -> queueMicrotask -> then3 -> set1 -> then2 -> then4 -> set2
인터뷰 질문 <2>
테스트 포인트: main script
, setTimeout
, Promise
, then
, queueMicrotask
, await
, async
지식 보충: async, wait는 구문 설탕입니다. for Promise
이벤트 루프 문제를 처리할 때,
new Promise((resolve,rejcet) => { 函数执行})
에 래핑된 코드로 간주할 수 있습니다then(res => {函数执行})
비동기 함수 async1() {의 then(res => {함수 실행}) 코드로
console.log('async1 시작'); 비동기2()를 기다립니다 console.log('async1 end'); } 비동기 함수 async2() { console.log('async2'); } console.log('스크립트 시작'); setTimeout(() => { console.log('setTimeout'); }, 0) 비동기1() 새로운 약속(해결 => { console.log('promise1'); 해결하다() }).then(() => { console.log('promise2'); }) console.log('스크립트 종료'); // 스크립트 시작 // 비동기1 시작 // 비동기2 // 약속1 // 스크립트 끝 // 비동기1 끝 // 약속2 // setTimeout은
시작 부분에 있는 함수 정의이며 첫 번째 console
문을 만날 때까지 실행을 위해 함수 호출 스택에 푸시될 필요가 없습니다. 스택을 푸시한 후 인쇄 script start
실행한 다음 이를 팝합니다. 타이머
timer
매크로 작업 대기열에 setTimeout
async1 함수가 실행됩니다. 먼저 async1 start
인쇄된 다음 await
문 뒤의 async2
함수가 실행됩니다. 앞서 언급한 것처럼 wait 키워드 뒤의 함수는 new Promise
이 함수가 즉시 실행되므로 async2가 출력되지만, wait 문 뒤의 코드는 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
입니다
.
script start -> async1 start -> async2 -> promise1 -> script end -> async1 end -> promise2 -> setTimeout