ホームページ > 記事 > ウェブフロントエンド > Nodejs のモジュール性とイベント ループについて話しましょう
この記事では、Nodejs のモジュール化とイベント ループについて理解します。一定の参考値があるので、困っている友達が参考になれば幸いです。
5.20 は、ブラウザ上で Node.js を実行できるオンライン Ide をリリースしました —WebContainers
Node.js とは正確には何ですか?私が学習を始めた頃は、一部のフロントエンドの知識領域にはあまり触れていませんでした (もちろん今でも同じですが) Node.js に対する印象は、構文が Javascript とほぼ同じであるということでした。バックエンドを書きます。当時、JavaScript を学ぶ=すべてを知ることができて、密かにうれしかったのを覚えています。さて、本題に入りましょう
[推奨学習: "nodejs チュートリアル "]
これまで、JavaScript はブラウザ上で実行されていました。レベル言語 コンピュータ 直接読むことはできません 結局のところ、バイナリコンピュータの世界には 010101 しかありません このとき、ブラウザの JavaScript エンジンが翻訳者として機能し、JavaScript がやりたいことを段階的にコンピュータに翻訳しますコンパイルプロセスについては詳しく説明しません(まだ説明できません)。
Node.js は Chrome ブラウザの V8 エンジンをベースにしており、効率的に Javascript をコンパイルできるため、Node.js はブラウザ以外のもう 1 つの Javascript 実行環境であると言えます。
Tencent Cloud のクラウド機能で WeChat 公開アカウントへの簡単な自動応答をいじっていたのを覚えていますが、当時、Node.js のおかげでフロントエンド コードのモジュール化について少し経験がありました。 !
server.jsファイルは以下の通りです
// 引入 http 模块 var http = require("http"); // 用 http 模块创建服务 //req 获取 url 信息 (request) //res 浏览器返回响应信息 (response) http.createServer(function (req, res) { // 设置 HTTP 头部,状态码是 200,文件类型是 html,字符集是 utf8 //Content-Type字段用于定义网络文件的类型和网页的编码,决定浏览器将以什么形式、什么编码读取这个文件,不写就可能会出现乱码哦 res.writeHead(200, { "Content-Type": "text/html;charset=UTF-8" }); // 往页面打印值 res.write('小林别闹'); // 结束响应 res.end(); }).listen(3000); // 监听3000端口
Nodeのインストール後にターミナルで実行してくださいnodeサーバー.js
ブラウザを開いてアドレス バーに http://localhost:3000/
と入力すると、ページが印刷されるのが表示されます:
var http = require("http"); このようなステートメントは、
http モジュールを導入するために使用されます。Node では、モジュールは 2 つのカテゴリに分類されます。1 つは、によって提供されるモジュールです。ノード。コア モジュールと呼ばれます。2 番目は、ユーザーが作成したモジュールで、ファイル モジュールと呼ばれます。
http は、コア モジュールの 1 つです。たとえば、
http モジュールを使用して、サービスの作成、および
path モジュールの処理 ファイル パス、
url モジュールは URL の処理と解析に使用されます
fs モジュールは、システム ファイルとディレクトリの読み取りと書き込みに使用されます
script タグの導入
jsファイル コードによって生成される依存関係シーケンスはエラーが発生しやすく、最上位スコープによって引き起こされる変数汚染などの問題
#ここで、export
と exports
## の違い#test2.js は次のとおりです:
let str = require('./test1'); console.log(str)test1.js が次の場合:
let str1 = '小林别闹1' let str2 = '小林别闹2' exports.str1 = str1 exports.str2 = str2 console.log(module.exports === exports)ターミナルで実行
node test2.js
結果は次のようになります。/*输出 { str1: '小林别闹1', str2: '小林别闹2' } true */ //改变test1.js文件变量暴露的方式 /* exports.str1 = str1 module.exports = str2 console.log(module.exports === exports) 输出: false 小林别闹2 */ /* exports.str1 = str1 module.exports.str2 = str2 console.log(module.exports === exports) 控制台输出: true { str1: '小林别闹1', str2: '小林别闹2' } */
は次のように要約できます:
Node がファイルを実行すると、exports
が file. オブジェクトとmodule オブジェクトに生成されます。この
module オブジェクトには
exports という別の属性があり、
exports は
module.exports 参照のペアであり、同じアドレスを指します。ただし、最後のエクスポートは
module.exports ですが、2 番目のテスト
module.exports = str2 でアドレスが変更されたため、
str1 はエクスポートされません。 ## また、
exports を使用してエクスポートすることは、オブジェクトをエクスポートすることであることに注意してください
2.1.2 Es Module#Javascript も常に開発され、進歩しています。いいえ、
Export:<pre class="brush:js;toolbar:false;">export const str1 = &#39;小林别闹1&#39;
export const str2 = &#39;小林别闹2&#39;
export default {
fn() {},
msg: "小林别闹"
}</pre>
Import: <pre class="brush:js;toolbar:false;">import { st1,str2,obj } from &#39;./test.js&#39;</pre>
Note# が追加されました。 ##import
node
js ファイルを直接実行するとエラーが報告されるので、babel でコンパイルする必要があります。比較すると次のようになります。CommonJs はステートメントを動的にロードでき、コードは実行時に発生します
Es モジュールは静的で、ステートメントを動的にロードできません。これはファイルの先頭でのみ宣言でき、コードはコンパイル時に発生します
2.1.3 サードパーティ モジュール
##Node で自分が提供するコア モジュールとカスタム モジュールを使用することに加えて、
サードパーティモジュール##
这就需要提到 npm
,npm
是 Node 的包管理工具,已经成为了世界上最大的开放源代码的生态系统,我们可以下载各种包.
当然包管理工具还有yarn
,但是我暂时只用过 npm
,因为它随 node
一起按照提供.
Java、PHP 或者 .NET 等服务端语言,会为每一个客户端的连接创建一个新的线程。Node 不会为每一个客户连接创建一个新的线程,而仅仅使用一个线程。
console.log('1') setTimeout(() => { console.log('2') }) console.log('3')//输出132
Javascript 的代码是从上到下一行行执行的,但是这里就不会阻塞,输出3,再输出2
Node 的事件循环真的好久才弄懂一丢丢,看过很多博客,觉得理解 Node 的事件循环机制,结合代码及其运行结果来分析是最容易理解的。
libuv 库负责 Node API 的执行。它将不同的任务分配给不同的线程,形成一个 Event Loop(事件循环),以异步的方式将任务的执行结果返回给 V8 引擎。其中 libuv 引擎中的事件循环分为 6 个阶段,它们会按照顺序反复运行。每当进入某一个阶段的时候,都会从对应的回调队列中取出函数去执行。当队列为空或者执行的回调函数数量到达系统设定的阈值,就会进入下一阶段。
console.log('start') setTimeout(() => {//定时器1 console.log('timer1') setTimeout(function timeout () {//定时器2 console.log('timeout'); },0); setImmediate(function immediate () {//定时器3 console.log('immediate'); }); Promise.resolve().then(function() { console.log('promise1') }) }, 0) setTimeout(() => {//定时器4 console.log('timer2') Promise.resolve().then(function() { console.log('promise2') }) }, 0) Promise.resolve().then(function() { console.log('promise3') }) console.log('end')
可以 Node 上边运行一下
timers 阶段:这个阶段执行timer(setTimeout、setInterval)的回调
I/O callbacks 阶段:处理一些上一轮循环中的少数未执行的 I/O 回调
idle, prepare 阶段:仅node内部使用
poll 阶段:获取新的I/O事件, 适当的条件下node将阻塞在这里
check 阶段:执行 setImmediate() 的回调
close callbacks 阶段:执行 socket 的 close 事件回调
理解:首先执行同步任务,所以会输出start end
,poll阶段是事件循环的入口,有异步事件就是从这里进入的,同步任务执行完执行先微任务,输出 promise3
,接下来就是 setTimeout
了,由 poll
阶段一步步到 timers
阶段,执行定时器1,输出 timer1
,将定时器2和定时器3加入到队列里边,一旦执行一个阶段里的一个任务就立刻执行微任务队列,所以再输出 promise1
,然后执行定时器4,如上输出timer2,promise2
,结合事件再循环,到了 check
阶段,执行 setImmediate() 的回调,输出 immediate
,再循环进行,到达 timer
阶段,输出 timeout
浏览器和 Node 的事件循环是不一样的
打算用两张图和一段代码来解释浏览器的事件循环机制,
console.log(1) setTimeout(()=>{console.log(2)},1000)//宏任务1 async function fn(){ console.log(3) setTimeout(()=>{console.log(4)},20)//宏任务2 //return Promise.reject()返回失败状态的,不会输出6,弄不清楚为啥 return Promise.resolve() } async function run(){ console.log(5) await fn() //console.log(6), } run() //需要执行150ms左右 for(let i=0;i<90000000;i++){} setTimeout(()=>{//宏任务3 console.log(7) new Promise(resolve=>{ console.log(8) resolve() }).then(()=>{console.log(9)}) },0) console.log(10) // 1 5 3 10 4 7 8 9 2
执行结果如(请忽略我的工具提示):
我们可以储备一些前置知识:JavaScript 是单线程的,任务可以分为同步任务和异步任务,像 console.log('1')
就是同步的,定时器 setTimeout
,promise
的回调等就是异步的。同步的很好理解,就从上到下一行一行的执行下来,异步的就有点小复杂了,还会分为宏任务和微任务。
浏览器的事件循环机制就是:先执行同步任务,同步任务执行完成,就执行任务队列里面的任务,那任务队列里面的任务是哪来的呢?异步任务准备好了就会放进任务队列,你可以理解为,在任务队列里边宏任务和微任务都存在这一个队列结构管着它们。先后的话,同步任务执行完成后,任务队列里有微任务,则将微任务执行完,再执行一个宏任务,执行了宏任务可能又产生了微任务,这是就需要再执行完微任务任务。你可以将同步任务看成宏任务,这样就可以理解为,每执行完一个宏任务都要清理一遍微任务。
上記のコードを以下のように説明します。コードの 1 行目が実行されると 1
が出力され、コードの 2 行目が実行されると setTimeout
がマクロに属します。タスク 1 が実行され、1000 ミリ秒後にタスク キューに追加される準備が整います。その後、関数 run
を実行し、出力 5
を実行します。await
が存在するため、 fn
関数が実行されるのを待つ必要があります。ここで ## を渡します。 #await キーワードは、非同期関数を同期関数に変えます。
fn が実行されると、 、
3 が出力され、別の
setTimeout マクロ タスク 2 が表示され、準備時間が 20 ミリ秒で、成功ステータス
Promise が返され、出力
6 ,
for ループには 150 ミリ秒かかります。これはマクロ タスク 2 です。準備が完了したら、タスク キューに入り、下に進みます。
setTimeout マクロ タスク 3 があります。タスク キューに参加するための準備は必要ありません。コードの最後の行を実行し、
10 を出力します。この時点で、すべての同期タスクが実行されました。次は非同期タスクであるタスク キューです。は、先入れ先出しの原則に従うキューのデータ構造です。この時点で、タスク キューにはマクロタスク 2 とマクロタスク 3 があります。マクロタスク 2 が最初に実行され、
4 が出力されます, そして、マクロタスク 3 が実行され、## が出力されます。#7
、promise
自体は同期であり、出力 8
、コールバック then
。内部はマイクロタスクです。マクロタスク 3 が実行されると、マイクロタスクが存在することがわかります。マイクロタスクの片側をクリーンにして、9
を出力します。プロセス全体の 1000 ミリ秒後、マクロタスク 1 がタスクに参加しますキューと出力 2
. ここを見てください. お兄さんのブログの方が分かりやすいかもしれませんが、文章はあまり良くありません. 申し訳ありませんが、リンクは以下です。
うまく書けないととても恥ずかしいですが、勉強します! ! !
プログラミング関連の知識について詳しくは、
プログラミング ビデオ以上がNodejs のモジュール性とイベント ループについて話しましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。