
データバイナリ
コンピュータ内のすべてのコンテンツ (テキスト、数値、画像、オーディオ、ビデオ) は最終的にバイナリで表現され
、
JS列などの非常に直感的なデータを直接処理できます。
画像
JSまたはHTMLによってブラウザに処理されます。ブラウザは画像のアドレスただし、サーバーでは、
utf-8ではなくGBKでエンコードされますBuffer読み取って処理する役割を担う、 sharpというライブラリがあります。Nodeでは、 TCP介して長い接続が確立され、バイトが送信されます。データは渡される前にバイトに変換され、送信されるバイトのサイズを知る必要があります (クライアントはサイズに基づいて読み取るコンテンツの量を判断する必要があります)。バッファとバイナリが
わかります。フロントエンド開発では、通常、バイナリ相互の処理に関連することはほとんどありませんが、サーバーサイドでは、多くの機能を実装するために、そのバイナリデータを直接操作する必要がある
ため、開発者がより多くの機能を完了しやすくすることができます
, Node Bufferという名前のクラスを提供しており、これはグローバルです
前に述べたように、バイナリ データは Buffer に保存されますが、どのように保存されるのでしょうか。
8ビットのバイナリ00000000格納できます。これはちょうど 1 バイトです。なぜ 8 ビットなのでしょうか。
1 byte = 8 bitのbyteと呼ばれます。1 byte = 8 bit 、 1kb = 1024 byte 、 1M = 1024kb 、 1 G = 1024 Mint型は4バイト、 long型は8バイトです。TCP For を送信します。バイトストリームの場合、書き込み時と読み取り時にバイト数を指定する必要があります。RGBの値はそれぞれ255であるため、本質的に、バッファーと文字列
Buffer 1 バイトでコンピューターに保存されます。バイトの配列に相当します。配列内の各項目のサイズは 1 バイトです。
文字列をバッファーに入れたい場合は、どのようなプロセスを実行すればよいでしょうか。
const message = 'Hello'
buffer// new キーワードを使用してバッファ インスタンスを作成しますが、この作成メソッドの有効期限が切れています constbuffer = new Buffer(message) console.log(buffer); // <バッファ 48 65 6c 6c 6f> console.log(buffer.toString()); // こんにちは、
中国語の文字列のエンコードとデコードです。
bufferのデフォルトのエンコードはutf-8なので、次のコードでは、 Bufferクラスは文字列のエンコードに utf-8 を使用します。文字列のデコードにも utf-8 を使用します。utf3バイトのバイナリ エンコードconst message = 'Hello'に対応します。
// Buffer.from を使用して文字列をデコードします constbuffer = Buffer.from(message) console.log(buffer); // <バッファ e4 bd a0 e5 a5 bd e5 95 8a> // エンコードをデコードできる toString メソッドがバッファ インスタンスにあります console.log(buffer.toString()); // 'Hello'
、エンコードとデコードで異なる形式のエンコード結果が使用される場合はどうなりますか?
const message = 'Hello' const バッファ = Buffer.from(メッセージ, 'utf16le') console.log(buffer); // <バッファ 60 4f 7d 59 4a 55> console.log(buffer.toString()); // `O}YJU
バッファを作成する他の方法
ここでは、alloc を使用してバッファ インスタンスを直接作成
buffer Buffer alloc
各 1 ビットが変更されます。
バッファの桁数を指定できます。たとえば、ここに 8 が渡された場合、作成されるバッファには 8 つの要素が含まれ、各要素に対応する 2 進数は 0 になります。 const バッファ = Buffer.alloc(8) console.log(buffer); // <バッファ 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>
})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 = 'Haha'
const バッファ = Buffer.from(msg, 'utf-8')
console.log(buffer.toString('utf16le')); // 2. 画像をコピーする目的を達成するために、画像ファイルは
画像エンコーディングをコピーします。
encoding属性を指定しないでください。fs = require('fs') を
fs.readFile('./logo.png', (err, data) => {
console.log(data); // 出力されるのは、画像ファイルに対応するバイナリ エンコーディングです。 // 画像エンコーディングを別のファイルに書き込むこともできます。これは、画像をコピーするのと同じです。 fs.writeFile(' ./bar) .png'、データ、エラー => {
コンソール.ログ(エラー);
})
})sharpライブラリconst Sharp = require('sharp')を使用できます。
// logo.png 画像を 200x300 にトリミングし、bax.png ファイルにコピーします Sharp('./logo.png')
.resize(200, 300)
.toFile('./bax.png', (err, 情報) => {
コンソール.ログ(エラー);
})
// 最初に画像ファイルをバッファに変換してから、画像をファイルに書き込むこともできます。sharp('./logo.png')
.resize(300, 300)
.toBuffer()
.then(データ => {
fs.writeFile('./baa.png', data, err => {
コンソール.ログ(エラー);
})
})バッファ作成プロセス
Bufferまず8 * 1024バイト、つまり8kbのメモリが適用されます。イベントループとは何ですか?
イベントループとは何ですか?
JSとブラウザーまたはNodeの間のブリッジとして理解しています。JSコードとブラウザー API 呼び出し ( setTimeout 、 AJAX 、监听事件など) の間のリンクです。 ) ブリッジはコールバック関数を通じて通信します。file system 、 networなど) の間のブリッジです。
プロセスとスレッド
プロセスとスレッドは、オペレーティング システムにおける 2 つの概念です。
process ): コンピューターが実行するプログラムthread ): オペレーティング システムが計算スケジュールを実行できる最小単位で、 CPU直接操作できます。スレッドは非常に抽象的に聞こえますが、直感的に説明しましょう。
説明するために、いくつかの例を示します
。複数
のプロセス (音楽を聴きながら、コードを書きながら) を実行できます。 、情報の確認)を同時に行いますか?

CPUの計算速度が非常に速く、複数のプロセスをすばやく切り替えることができるため、
ブラウザと JavaScript
JavaScriptはシングルスレッドであるとよく言われますが、JS スレッドには独自のコンテナ プロセスが必要ですNode
ブラウザまたは Node ブラウザはプロセスですか? スレッドは 1 つだけですか?
tabが停止してすべてのページが応答しなくなるのを防ぐためです。ただし、JavaScript コードの実行は、同時に
JSのことしか実行できません。JavaScript の実行処理
関数は、関数呼び出しスタックにプッシュされるまで実行されないので、
const message = 'Hello World ' というコードの実行処理を分析してみましょう。
console.log(メッセージ);
関数 sum(num1, num2) {
num1 + num2 を返す
}
関数 foo() {
const 結果 = sum(20, 30)
console.log(結果);
}
foo()main関数で実行されるとみなすことができますmessageを定義しlog関数を実行するfoo関数を呼び出します。ただし、foo 関数は実行中に呼び出される必要がsumjsコード全体が実行され、main 関数がブラウザのイベント ループ
からポップアウトされますJSコードの実行中に非同期操作があった場合はどうなるでしょうか。
setTimeout関数呼び出しを途中に挿入するとその後、関数は setTimeout 関数に渡されます。 (これをtimer機能と呼びます)、いつ実行されますか?
web api呼び出し、適切なタイミングで、タイマー関数がイベント キューに追加され、setTimeout がコードの実行をブロックしないのはなぜですか
?これは、ブラウザーが非常に重要なことを維持しているためです。イベント ループ
ブラウザーは、コールバック関数を何らかの方法で setTimeout に保存するのに役立ちます。より一般的な方法は、コールバック関数を赤黒ツリーに保存し
、setTimeout がスケジュールされるまで待つこと
タイマー時間になると、タイマー コールバック関数が保存された場所から取り出され、
イベント ループがキューに何かがあり、現在の関数呼び出しスタックが空であることが検出されると、それがイベント キューに入れられます
同期コードが実行されると、キュー内のコールバック関数がデキューされ、実行のために関数呼び出しスタックに置かれます (
もちろん
、キュー内の前の関数がポップアウトされるまで、次の関数はスタックにプッシュされません)。たとえば、特定のプロセス中にユーザーがブラウザーでボタンをクリックすると、コールバック関数に対応するこのボタンのクリックを監視することがあります。キューにも追加されます。実行順序は、イベント キュー内の順序に基づきます。イベント キューにajaxリクエストを送信するコールバックの概要もあります
。実際、イベント ループは非常に単純なもので、特別な状況下で特定のコールバックを実行する必要がある場合に、コールバックが保存されることを意味します。事前にイベント キューに詰め込まれ、イベント ループがそれを取り出して関数呼び出しスタックに置きます。

macrotask queueタスク
ただし、イベント ループはキューを 1 つだけ保持するわけではなく、キュー内のタスクの実行はすべてのスクリプトが実行される
ajaxsetTimeout 、 setInterval 、 DOMモニタリング、 UI Rendering 、およびその他のmicrotask queue ): Promiseのthenコールバック、 Mutation Observer API 、 queueMicrotask()など。では、イベント ループ内の 2 つのキューの優先順位は何でしょうか?
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');
})
コンソール.ログ(2);
queueMicrotask(() => {
console.log('queueMicrotask');
})
新しい約束(解決 => {
解決する()
}).then(() => {
console.log('then3');
})
// pr1
// 2
//その後1
//キューマイクロタスク
//それで3
// セット1
//その後2
//それで4
// set2 setTimeout関数呼び出しスタックにすぐにプッシュされ、実行後すぐにスタックからポップアウトされます。そのtimer関数はマクロ タスク キューに入れられ、
Promiseクラスに渡された関数はすぐに実行されます。これはコールバック関数ではないため、 pr1が出力され、 resolveメソッドが実行されるため、Promise のステータスが即座にfulfilledに変更され、 then関数が実行されると、対応するコールバック関数が実行されます。
スタックがポップされると、関数が
スタックにプッシュされconsole.log 2
キュー
ここで関数がqueueMicrotaskにバインドされ、関数が配置されます
。
新しい Promise ステートメントが検出されましたが、すぐに Promise ステータスがフルフィルメントに変更されたため、コールバック
then 関数に対応するタスクもマイクロタスク キューに入れられました。
同期スクリプト コードが実行されたため、ループの開始時に、マイクロタスク キューおよびマクロタスクと競合するタスクがマイクロタスク キューに入れられます。注: マイクロタスクの優先順位は、マクロタスクを実行する前に毎回読み取る必要があります。空ではないので、
最初のマイクロタスクはthen1印刷し、3 番目のマイクロタスクはthen3印刷します。その後、実行が完了します。
マクロ
タスクはより複雑で、最初にset1を出力し、その後、そのnew promiseバックがマイクロタスク キューに入れられることに注意してください。キューは空ではないため、より高い優先度のマイクロタスク キューを実行する必要があります。これは、同じ新しい Promise ステートメントであり、対応する then スワップがマイクロタスク キューに入れられる、then コールバックと同等です。新しい Promise ステートメントの後にconsole関数があることに注意してください。この関数は、新しい Promise ステートメントの実行直後に実行されます。 then2 、マイクロタスク対立にはタスクがまだ残っているため、次のステップは print です。 then4 .これまでのところ、マイクロタスク キューは空であり、マクロタスク キューは引き続き実行できるため
、マクロタスクが実行された後、次のマクロタスクset2が出力され、
コード全体の出力結果はpr1 -> 2 -> then1 -> queueMicrotask -> then3 -> set1 -> then2 -> then4 -> set2
面接の質問 <2>
テストポイント: main script 、 setTimeout 、 Promise 、 then 、 queueMicrotask 、 await 、 async
知識補足: async、await は構文シュガーですイベントループのPromiseを扱う場合、
new Promise((resolve,rejcet) => { 函数执行})でラップされたコードとみなすことができますthen(res => {函数执行})非同期関数 async1() {の then(res => {関数実行}) のコードとして
console.log('async1 start');
async2()を待つ
console.log('async1 終了');
}
非同期関数 async2() {
console.log('async2');
}
console.log('スクリプト開始');
setTimeout(() => {
console.log('setTimeout');
}、0)
async1()
新しい約束(解決 => {
console.log('promise1');
解決する()
}).then(() => {
console.log('promise2');
})
console.log('スクリプト終了');
// スクリプトの開始
// async1 開始
// 非同期2
// 約束1
// スクリプト終了
// async1 終了
// 約束2
// setTimeoutは最初の関数定義であり、最初のconsoleステートメントに遭遇するまで、実行のために関数呼び出しスタックにプッシュする必要はありません。スタックをプッシュした後、印刷script start 、スクリプトをポップアウトします。これは
setTimeout timerマクロ タスク キューに入れられ
、async1 関数が実行されます。まず、 async1 startが出力され、次にawaitステートメントの後のasync2関数が実行されます。前述したように、 await キーワードの後の関数はnew Promiseとしてみなされるため、この関数はすぐに実行され、 async2 が出力されますが、 await ステートメントの後のコードは then に置かれたのと同じです。 callback、つまりconsole.log('async1 end')このコード行はマイクロタスク キューに入れられ
、コードは実行を続けます。そのため、 promise1関数がすぐに出力されます。次に、コールバックがマイクロタスク キューに入れられ、
印刷用の最後のコンソール関数が実行されます。同期script endが実行されます。
まず、
最初のマイクロタスクに対応する print ステートメントが実行されます。つまり、 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