1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        一文搞懂Node.js以及瀏覽器中的事件循環(huán)機(jī)制

        共 11531字,需瀏覽 24分鐘

         ·

        2020-10-10 01:05

        原文轉(zhuǎn)自:Node.js VS 瀏覽器以及事件循環(huán)機(jī)制 https://juejin.im/post/6871832597891121166

        本文主要梳理node.js,瀏覽器相關(guān)及Event Loop事件循環(huán)等,會(huì)持續(xù)補(bǔ)充更新哦!首先我們要記住JS是一個(gè)單線(xiàn)程的語(yǔ)言。

        JS同步異步

        • 同步阻塞
        • **異步非阻塞:**在涉及需要等待的操作,我們選擇讓程序繼續(xù)運(yùn)行,在等待時(shí)間結(jié)束的時(shí)候,通知一下我們的程序內(nèi)容執(zhí)行完畢,你可以操作這些資源了,這段等待時(shí)間并不影響你程序的繼續(xù)執(zhí)行,只是在未來(lái)的某個(gè)時(shí)間段(不確定),有一個(gè)操作一定會(huì)執(zhí)行。

        JS的異步方案演進(jìn)史

        Raw Callback Style -> Promise Callback Style -> Generator Callback Style -> Async/Await Callback
        任務(wù)隊(duì)列:先進(jìn)先出

        JS Engine 和 JS Runtime

        • **Engine(執(zhí)行引擎):**如V8 Engine,V8 實(shí)現(xiàn)并提供了 ECMAScript 標(biāo)準(zhǔn)中的所有數(shù)據(jù)類(lèi)型、操作符、對(duì)象和方法(注意并沒(méi)有 DOM)。Event Loop 是屬于 JavaScript Runtime 的,是由宿主環(huán)境提供的(比如瀏覽器,node)
        • **Runtime(執(zhí)行環(huán)境):**Chrome 提供了 window、DOM,而 Node.js 則是 require、process 等等。

        JS執(zhí)行機(jī)制

        事件循環(huán)(Event Loop)是js實(shí)現(xiàn)異步的一種方法,也是js的執(zhí)行機(jī)制。

        • 同步和異步任務(wù)分別進(jìn)入不同的執(zhí)行"場(chǎng)所",同步的進(jìn)入主線(xiàn)程,異步的進(jìn)入Event Table并注冊(cè)函數(shù)。
        • 當(dāng)指定的事情完成時(shí),Event Table會(huì)將這個(gè)函數(shù)移入Event Queue。
        • 主線(xiàn)程內(nèi)的任務(wù)執(zhí)行完畢為空,會(huì)去Event Queue讀取對(duì)應(yīng)的函數(shù),進(jìn)入主線(xiàn)程執(zhí)行。
        • 上述過(guò)程會(huì)不斷重復(fù),也就是常說(shuō)的Event Loop(事件循環(huán))。

        怎么知道主線(xiàn)程執(zhí)行棧為空

        js引擎存在monitoring process進(jìn)程,會(huì)持續(xù)不斷的檢查主線(xiàn)程執(zhí)行棧是否為空,一旦為空,就會(huì)去Event Queue那里檢查是否有等待被調(diào)用的函數(shù)。

        執(zhí)行規(guī)則

        • 首先在執(zhí)行棧(call stack)中的內(nèi)容執(zhí)行完畢清空后,會(huì)在事件隊(duì)列(Event queue)檢查一下哪些是宏任務(wù)哪些是微任務(wù),然后執(zhí)行所有的微任務(wù),然后執(zhí)行一個(gè)宏任務(wù),之后再次執(zhí)行所有的微任務(wù)。也就是說(shuō)在主線(xiàn)程(main thread)任務(wù)執(zhí)行完畢后會(huì)把任務(wù)隊(duì)列中的微任務(wù)全部執(zhí)行,然后再執(zhí)行一個(gè)宏任務(wù),這個(gè)宏任務(wù)執(zhí)行完再次檢查隊(duì)列內(nèi)部的微任務(wù),有就全部執(zhí)行沒(méi)有就再執(zhí)行一個(gè)宏任務(wù)。
        • JS是單線(xiàn)程但是瀏覽器是多線(xiàn)程。你的異步任務(wù)是瀏覽器開(kāi)啟對(duì)應(yīng)的線(xiàn)程來(lái)執(zhí)行的,最后放入JS引擎中進(jìn)行執(zhí)行。
        • 所以在執(zhí)行定時(shí)器、事件、ajax這些異步事件的時(shí)候是另外三個(gè)線(xiàn)程在執(zhí)行代碼,并不是JS引擎在做事情,在這些線(xiàn)程達(dá)到某一特定事件把任務(wù)放入JS引擎的線(xiàn)程中,同時(shí)GUI線(xiàn)程(渲染界面HTMl的線(xiàn)程)與JS線(xiàn)程是互斥的,在JS引擎執(zhí)行時(shí)GUI線(xiàn)程會(huì)被凍結(jié)、掛起。

        瀏覽器主線(xiàn)程常駐線(xiàn)程

        • GUI 渲染線(xiàn)程

          • 繪制頁(yè)面,解析 HTML、CSS,構(gòu)建 DOM 樹(shù),布局和繪制等
          • 頁(yè)面重繪和回流
          • 與 JS 引擎線(xiàn)程互斥,也就是所謂的 JS 執(zhí)行阻塞頁(yè)面更新
        • JS 引擎線(xiàn)程

          • 負(fù)責(zé) JS 腳本代碼的執(zhí)行
          • 負(fù)責(zé)執(zhí)行準(zhǔn)備好待執(zhí)行的事件,即定時(shí)器計(jì)數(shù)結(jié)束,或異步請(qǐng)求成功并正確返回的事件
          • 與 GUI 渲染線(xiàn)程互斥,執(zhí)行時(shí)間過(guò)長(zhǎng)將阻塞頁(yè)面的渲染
        • 事件觸發(fā)線(xiàn)程

          • 負(fù)責(zé)將準(zhǔn)備好的事件交給 JS 引擎線(xiàn)程執(zhí)行
          • 多個(gè)事件加入任務(wù)隊(duì)列的時(shí)候需要排隊(duì)等待(JS 的單線(xiàn)程)
        • 定時(shí)器觸發(fā)線(xiàn)程

          • 負(fù)責(zé)執(zhí)行異步的定時(shí)器類(lèi)的事件,如 setTimeout、setInterval
          • 定時(shí)器到時(shí)間之后把注冊(cè)的回調(diào)加到任務(wù)隊(duì)列的隊(duì)尾
        • HTTP 請(qǐng)求線(xiàn)程

          • 負(fù)責(zé)執(zhí)行異步請(qǐng)求
          • 主線(xiàn)程執(zhí)行代碼遇到異步請(qǐng)求的時(shí)候會(huì)把函數(shù)交給該線(xiàn)程處理,當(dāng)監(jiān)聽(tīng)到狀態(tài)變更事件,如果有回調(diào)函數(shù),該線(xiàn)程會(huì)把回調(diào)函數(shù)加入到任務(wù)隊(duì)列的隊(duì)尾等待執(zhí)行

        宏任務(wù)和微任務(wù)

        • macro-task(宏任務(wù)):包括整體代碼script,setTimeout,setInterval,I/O、UI Rendering等
        • micro-task(微任務(wù)):Promise.then catch finally(注意不是說(shuō) Promise,new promise直接執(zhí)行),process.nextTick,MutationObserver

        setTimeout(fn,0)

        指定某個(gè)任務(wù)在主線(xiàn)程最早可得的空閑時(shí)間執(zhí)行,意思就是不用再等多少秒了,只要主線(xiàn)程執(zhí)行棧內(nèi)的同步任務(wù)全部執(zhí)行完成,棧為空就馬上執(zhí)行。(關(guān)于setTimeout要補(bǔ)充的是,即便主線(xiàn)程為空,0毫秒實(shí)際上也是達(dá)不到的。根據(jù)HTML的標(biāo)準(zhǔn),最低是4毫秒。)

        setInterval(fn,0)

        會(huì)每隔指定的時(shí)間將注冊(cè)的函數(shù)置入Event Queue,如果前面的任務(wù)耗時(shí)太久,那么同樣需要等待。每過(guò)ms秒,會(huì)有fn進(jìn)入Event Queue。一旦setInterval的回調(diào)函數(shù)fn執(zhí)行時(shí)間超過(guò)了延遲時(shí)間ms,那么就完全看不出來(lái)有時(shí)間間隔了

        requestAnimationFrame

        **請(qǐng)求動(dòng)畫(huà)幀,是一個(gè)宏任務(wù),**html5 提供的一個(gè)專(zhuān)門(mén)用于請(qǐng)求動(dòng)畫(huà)的API,相比起setTimeout由系統(tǒng)決定回調(diào)函數(shù)的執(zhí)行時(shí)機(jī)。60Hz的刷新頻率,那么每次刷新的間隔中會(huì)執(zhí)行一次回調(diào)函數(shù),不會(huì)引起丟幀,不會(huì)卡頓。

        Promise與process.nextTick(callback)

        process.nextTick(callback):類(lèi)似node.js版的"setTimeout",在事件循環(huán)的下一次循環(huán)中調(diào)用 callback 回調(diào)函數(shù)。
        不同類(lèi)型的任務(wù)會(huì)進(jìn)入對(duì)應(yīng)的Event Queue,比如setTimeout和setInterval會(huì)進(jìn)入相同的Event Queue。

        執(zhí)行和運(yùn)行的區(qū)別

        執(zhí)行和運(yùn)行有很大的區(qū)別,javascript在不同的環(huán)境下,比如node,瀏覽器,Ringo等等,執(zhí)行方式是不同的。而運(yùn)行大多指javascript解析引擎,是統(tǒng)一的。

        一些特殊的點(diǎn)

        • async 隱式返回 Promise 作為結(jié)果,執(zhí)行完 await 之后直接跳出 async 函數(shù),讓出執(zhí)行的所有權(quán),當(dāng)前任務(wù)的其他代碼執(zhí)行完之后再次獲得執(zhí)行權(quán)進(jìn)行執(zhí)行
        • 立即 resolve 的 Promise 對(duì)象,是在本輪"事件循環(huán)"的結(jié)束時(shí)執(zhí)行,而不是在下一輪"事件循環(huán)"的開(kāi)始時(shí)
        • 在一輪event loop中多次修改同一dom,只有最后一次會(huì)進(jìn)行繪制。
        • 渲染更新(Update the rendering)會(huì)在event loop中的tasks和microtasks完成后進(jìn)行,但并不是每輪event loop都會(huì)更新渲染,這取決于是否修改了dom和瀏覽器覺(jué)得是否有必要在此時(shí)立即將新?tīng)顟B(tài)呈現(xiàn)給用戶(hù)。如果在一幀的時(shí)間內(nèi)(時(shí)間并不確定,因?yàn)闉g覽器每秒的幀數(shù)總在波動(dòng),16.7ms只是估算并不準(zhǔn)確)修改了多處dom,瀏覽器可能將變動(dòng)積攢起來(lái),只進(jìn)行一次繪制,這是合理的。
        • 如果希望在每輪event loop都即時(shí)呈現(xiàn)變動(dòng),可以使用requestAnimationFrame。

        Node下的 Event Loop

        基于libuv實(shí)現(xiàn),而libuv是 Node 的新跨平臺(tái)抽象層,libuv使用異步IO事件驅(qū)動(dòng)的編程方式,核心是提供i/o的事件循環(huán)和異步回調(diào)。libuv的API包含有時(shí)間,非阻塞的網(wǎng)絡(luò),異步文件操作,子進(jìn)程等等。

        六個(gè)階段

        • timers:執(zhí)行setTimeout() 和 setInterval()中到期的callback。
        • pending callback: 上一輪循環(huán)中有少數(shù)的I/O callback會(huì)被延遲到這一輪的這一階段執(zhí)行
        • idle, prepare:僅內(nèi)部使用
        • poll: 最為重要的階段,執(zhí)行I/O callback,在適當(dāng)?shù)臈l件下會(huì)阻塞在這個(gè)階段
        • check: 執(zhí)行setImmediate的callback
        • close callbacks: 執(zhí)行close事件的callback,例如socket.on('close'[,fn])、http.server.on('close, fn)

        Node與瀏覽器的 Event Loop 差異

        • 瀏覽器環(huán)境下,microtask的任務(wù)隊(duì)列是每個(gè)macrotask執(zhí)行完之后執(zhí)行。
        • 而在Node.js中,microtask會(huì)在事件循環(huán)的各個(gè)階段之間執(zhí)行,也就是一個(gè)階段執(zhí)行完畢,就會(huì)去執(zhí)行microtask隊(duì)列的任務(wù)。

        node.js 是?個(gè) JS 的服務(wù)端運(yùn)?環(huán)境,簡(jiǎn)單的來(lái)說(shuō),是在 JS 語(yǔ)?規(guī)范的基礎(chǔ)上,封裝了?些服務(wù)端的運(yùn)?時(shí) 對(duì)象,讓我們能夠簡(jiǎn)單實(shí)現(xiàn)?常多的業(yè)務(wù)功能。> 基于 JS 語(yǔ)法增加與操作系統(tǒng)之間的交互。

        Node的簡(jiǎn)單介紹

        底層依賴(lài)

        node.js 的主要依賴(lài)?模塊有以下內(nèi)容:

        • V8 引擎:主要是 JS 語(yǔ)法的解析,有了它才能識(shí)別JS語(yǔ)法
        • libuv: c 語(yǔ)?實(shí)現(xiàn)的?個(gè)?性能異步?阻塞 IO 庫(kù),?來(lái)實(shí)現(xiàn) node.js 的事件循環(huán)
        • http-parser/llhttp: 底層處理 http 請(qǐng)求,處理報(bào)?,解析請(qǐng)求包等內(nèi)容
        • openssl: 處理加密算法,各種框架運(yùn)??泛
        • zlib: 處理壓縮等內(nèi)容

        常見(jiàn)內(nèi)置模塊

        • fs: ?件系統(tǒng),能夠讀取寫(xiě)?當(dāng)前安裝系統(tǒng)環(huán)境中硬盤(pán)的數(shù)據(jù)
        • path: 路徑系統(tǒng),能夠處理路徑之間的問(wèn)題
        • crypto: 加密相關(guān)模塊,能夠以標(biāo)準(zhǔn)的加密?式對(duì)我們的內(nèi)容進(jìn)?加解密
        • dns: 處理 dns 相關(guān)內(nèi)容,例如我們可以設(shè)置 dns 服務(wù)器等等
        • http: 設(shè)置?個(gè) http 服務(wù)器,發(fā)送 http 請(qǐng)求,監(jiān)聽(tīng)響應(yīng)等等
        • readline: 讀取 stdin 的??內(nèi)容,可以讀取、增加、刪除我們命令?中的內(nèi)容
        • os: 操作系統(tǒng)層?的?些 api,例如告訴你當(dāng)前系統(tǒng)類(lèi)型及?些參數(shù)
        • vm: ?個(gè)專(zhuān)?處理沙箱的虛擬機(jī)模塊,底層主要來(lái)調(diào)? v8 相關(guān) api 進(jìn)?代碼解析。

        Buffer 緩沖

        Buffer 類(lèi),用來(lái)創(chuàng)建一個(gè)專(zhuān)門(mén)存放二進(jìn)制數(shù)據(jù)的緩存區(qū)。

        • Buffer 是 UInt8Array
        • 是數(shù)組,且每個(gè)item的有效范圍是 0~255(無(wú)符號(hào)8位)
        • 詳細(xì)api可查 [nodejs.cn/api/buffer.…][nodejs.cn_api_buffer.]
        ????Buffer.from([1,?1,?1,?1]);?//Buffer.from()?接口創(chuàng)建Buffer對(duì)象(傳入的array的元素只能是數(shù)字,不然就會(huì)自動(dòng)被0覆蓋)
        ????Buffer.from([257,?257.5,?-255,?'1']);?//都是1
        ????Buffer.from('abcd');?//utf8編碼轉(zhuǎn)換?
        ????const?bf?=?Buffer.alloc(256);?//創(chuàng)建一個(gè)長(zhǎng)度為?256、且用?0?填充的?Buffer
        ????const?len?=?buf.write("www.baidu.com");?//寫(xiě)入,返回實(shí)際寫(xiě)入的大小。如果 buffer 空間不足,?則只會(huì)寫(xiě)入部分字符串。
        ????const?str1?=?buf.toString('utf8')?////?使用?'utf8'?編碼,?并輸出:?www.baidu.com
        ????const?str2?=?buf.toString('utf8',0,9)?////?使用?'utf8'?編碼,?并輸出:?www.baidu

        EventEmitter 事件

        events 模塊只提供了一個(gè)對(duì)象:events.EventEmitter。EventEmitter 的核心就是事件觸發(fā)與事件監(jiān)聽(tīng)器功能的封裝。

        • **on方法,**注冊(cè)事件回調(diào)
        • **emit方法,**手動(dòng)觸發(fā)事件
        • 詳細(xì)api可查** **[nodejs.cn/api/events.…][nodejs.cn_api_events.]
        ????const?EventEmitter?=?require('events');
        ????class?MyEventEmitter?extends?EventEmitter?{}
        ????const?myEventEmitter?=?new?MyEventEmitter();
        ????myEventEmitter.on('ping',?function()?{
        ?????console.log('pong');
        ????})
        ????myEventEmitter.emit('ping');

        Stream 流

        Stream 是一個(gè)抽象接口,Node 中有很多對(duì)象實(shí)現(xiàn)了這個(gè)接口。例如,對(duì)http 服務(wù)器發(fā)起請(qǐng)求的request 對(duì)象就是一個(gè) Stream,還有stdout(標(biāo)準(zhǔn)輸出)

        • Stream 有四種流類(lèi)型

          • Readable - 可讀操作
          • Writable - 可寫(xiě)操作
          • Duplex - 可讀可寫(xiě)操作
          • Transform - 操作被寫(xiě)入數(shù)據(jù),然后讀出結(jié)果
        • Stream 對(duì)象本身就是一個(gè) EventEmitter ,常用事件有

          • data - 當(dāng)有數(shù)據(jù)可讀時(shí)觸發(fā)。

          • end - 沒(méi)有更多的數(shù)據(jù)可讀時(shí)觸發(fā)。

          • error - 在接收和寫(xiě)入過(guò)程中發(fā)生錯(cuò)誤時(shí)觸發(fā)。

          • finish - 所有數(shù)據(jù)已被寫(xiě)入到底層系統(tǒng)時(shí)觸發(fā)。

        • Stream 內(nèi)部含有 Buffer

        • Stream優(yōu)勢(shì):只會(huì)先讀文件需要的一部分,內(nèi)存損耗較小

        • 詳細(xì)api可查** **[nodejs.cn/api/stream.…][nodejs.cn_api_stream.]

          var readerStream = fs.createReadStream('input.txt',{start:50,end:99}); //讀取一部分

        常見(jiàn)全局對(duì)象

        • setTimeout 創(chuàng)建定時(shí)
        • clearTimeout(t) 停止定時(shí)
        • setInterval 創(chuàng)建輪詢(xún)
        • clearInterval(t) 停止輪詢(xún)
        • console 打印
        • process 進(jìn)程

        模塊全局對(duì)象

        模塊加載時(shí)注入

        • __filename 模塊文件的路徑
        • __dirname 當(dāng)前執(zhí)行腳本所在的目錄
        • exports 輸出
        • module 模塊
        • require 請(qǐng)求

        npm(node package manager)

        • node.js 內(nèi)置的用于安裝和發(fā)布符合 node.js 標(biāo)準(zhǔn)的模塊的?款?具,從?實(shí)現(xiàn)社區(qū)共建的?的繁榮整個(gè)社區(qū)。

        • npx 是 npm@5 之后新增的?個(gè)命令,它使得我們可以 在不安裝模塊到當(dāng)前環(huán)境的前提下,使??些 cli 功能,每次調(diào)用都會(huì)使用最新的版本。

          全局安裝了 vue

          npm i -g vue vue init webpack test

          ?論是項(xiàng)?中還是全局都沒(méi)有安裝 vue (但實(shí)際上是安裝了的,但表現(xiàn)確實(shí)像沒(méi)有安裝)

          npx vue test

        發(fā)布一個(gè)npm包

        • 安裝webpack簡(jiǎn)易框架(這里以發(fā)布vue插件為例)
        ????npm?install?-g?@vue/cli-init?//cli版本是3及以上,vue?init?的運(yùn)行效果將會(huì)跟[email protected]?相同
        ????vue?init?webpack-simple?marquee
        ????//安裝完成目錄結(jié)構(gòu)
        ????文件目錄/
        ????├──?index.html
        ????├──?package.json
        ????├──?README.md
        ????├──?.babelrc
        ????├──?.editorconfig
        ????├──?.gitignore
        ????├──?src
        ????│???├──?App.vue
        ????│???├──?assets
        ????│???│???└──?logo.png
        ????│???└──?main.js
        ????└──?webpack.config.js
        • 封裝Vue插件(創(chuàng)建一個(gè)index.js)

          //在APP.vue中查看效果 npm install npm run dev

        • 在index.js中export封裝好的Vue插件

        • 修改webpack.config.js

        ????const?NODE_ENV?=?process.env.NODE_ENV;
        ????module.exports?=?{
        ??????entry:?NODE_ENV?==?'development'???'./src/main.js'?:?'./src/marquee/index.js',
        ??????output:?{
        ????????path:?path.resolve(__dirname,?'./dist'),
        ????????publicPath:?'/dist/',
        ????????filename:?'marquee.js',?//輸出文件名
        ????????library:?'marquee',?//?指定的就是你使用require時(shí)的模塊名
        ????????libraryTarget:?'umd', //?指定輸出格式, UMD 同時(shí)支持兩種執(zhí)行環(huán)境:node環(huán)境、瀏覽器環(huán)境。
        ????????umdNamedDefine:?true?//?會(huì)對(duì) UMD 的構(gòu)建過(guò)程中的 AMD 模塊進(jìn)行命名。否則就使用匿名的 define
        ??????},
        ????}
        • 打包
        ????npm?run?build
        ????//出現(xiàn)dist文件夾
        • 修改package.json
        ????{
        ?????"author":?"maomincoding",??//author的值為npm用戶(hù)名,這里一定要注意
        ??????"main":?"dist/marquee.js",?//main的值為剛才打包的路徑文件
        ??????"license":?"ISC",?//license的值按照以上即可
        ??????"keywords":?["marquee"],?//keywords為用戶(hù)搜索的關(guān)鍵詞
        ??????"private":?false,?//private設(shè)為false,?開(kāi)源因此需要將這個(gè)字段改為?false
        ????}
        • 發(fā)包文件名單
        ????//npm發(fā)包默認(rèn)包含的文件(不區(qū)分大小寫(xiě))
        ????package.json
        ????README?(and?its?variants)
        ????CHANGELOG?(and?its?variants)
        ????LICENSE?/?LICENCE
        ????package.json屬性main指向的文件
        ????//npm發(fā)包默認(rèn)忽略的文件
        ????.git
        ????CVS
        ????.svn
        ????.hg
        ????.lock-wscript
        ????.wafpickle-N
        ????.*.swp
        ????.DS_Store
        ????._*
        ????npm-debug.log
        ????.npmrc
        ????node_modules
        ????config.gypi
        ????*.orig
        ????package-lock.json?(use?shrinkwrap?instead)
        ????//發(fā)包白名單,設(shè)置package.json中的files屬性
        ????files:["package.json","src"]
        ????//發(fā)包黑名單,通過(guò)下面兩個(gè)文件來(lái)設(shè)置忽略的文件或文件夾
        ????.gitignore
        ????.npmignore
        ????//文件設(shè)置優(yōu)先級(jí)!!!
        ????files>.npmignore>.gitignore
        • 編輯README.md
        • npm包發(fā)布
        ????npm?config?get?registry?//查看登錄源
        ????npm?config?set?registry=http://registry.npmjs.org?//如果不是http://registry.npmjs.org就切換一下
        ????npm?login?//登錄?回車(chē)出現(xiàn)?Logged?in?as?maomincoding?on?http://registry.npmjs.org,那么就成功了
        ??? npm publish //成功!
        • npm包撤銷(xiāo) :只有在發(fā)包的24小時(shí)內(nèi)才允許撤銷(xiāo),以后發(fā)包的時(shí)候也不能再和被撤銷(xiāo)的包的名稱(chēng)和版本重復(fù)了,建議慎重!I sure hope you know what you are doing
        ????npm?unpublish?包名?--force?//撤銷(xiāo)
        • npm包更新

          • 修復(fù)bug,小改動(dòng),c加1
          • 增加了新特性,但仍能向后兼容,b加1
          • 有很大的改動(dòng),無(wú)法向后兼容,a加1
          • 打開(kāi)根目錄下的package.json找到version字段 "version":"a.b.c"

          • 再次發(fā)布

        nvm(node version manager)

        管理 node 版本的?個(gè)?具,簡(jiǎn)單來(lái)說(shuō),就是通過(guò)將多個(gè) node 版本安裝在指定路徑,然后通過(guò) nvm 命令切換時(shí),就會(huì)切換我們環(huán)境變量中 node 命令指定的實(shí)際執(zhí)?的軟件路徑。

        nrm(npm registry manager )

        是npm的鏡像源管理工具,使用這個(gè)可以快速地在 npm 源間切換。

        服務(wù)端框架 express/koa

        node.js 內(nèi)部有?常多的內(nèi)置模塊,其中就有 http 模塊,express/koa 實(shí)際上就是 對(duì)這個(gè) http 模塊的再封裝,增加了中間件策略和其他 各種路由的通?處理,讓我們寫(xiě)起來(lái)更加?便。

        • body-parser express處理body的中間件
        • cookie-parser express處理cookie的中間件
        • 中間件可以這樣理解,對(duì)于需要多次書(shū) 寫(xiě)的業(yè)務(wù)邏輯,可以使??種切?的形式,對(duì)相同邏輯進(jìn)?通?處理。
        • **洋蔥模型:**中間件線(xiàn)性的連貫的,自上而下(垂直)依次進(jìn)行劫持。執(zhí)行到next()會(huì)跳出當(dāng)前繼續(xù)向下一個(gè)中間件執(zhí)行,結(jié)束后會(huì)返回之前中間件執(zhí)行next()后面內(nèi)容。
        • koa和express在同步場(chǎng)景下完全相同,處理異步時(shí)koa進(jìn)行rosolve能正確執(zhí)行回調(diào)順序,但express缺少這個(gè)方法,會(huì)產(chǎn)生一些順序問(wèn)題。

        周邊工具簡(jiǎn)介

        quickjs

        quickjs 是?個(gè) JS 的解析引擎,輕量代碼量也不?,與之功能類(lèi)似的就是 V8 引擎。
        他最?的特點(diǎn)就是,?常?常輕量,這點(diǎn)從源碼中也能提現(xiàn),事實(shí)上并沒(méi)有太多的代碼,它的主要特點(diǎn)和優(yōu)勢(shì):

        • 輕量?且易于嵌?:只需?個(gè)C?件,沒(méi)有外部依賴(lài),?個(gè)x86下的簡(jiǎn)單的“hello world”程序只要180KiB。
        • 具有極低啟動(dòng)時(shí)間的快速解釋器:在?臺(tái)單核的臺(tái)式PC上,?約在100秒內(nèi)運(yùn)?ECMAScript 測(cè)試套件156000次。運(yùn)?時(shí)實(shí)例的完整?命周期在不到300微秒的時(shí)間內(nèi)完成。
        • ?乎完整實(shí)現(xiàn)ES2019?持,包括:模塊,異步?成器和和完整Annex B?持 (傳統(tǒng)的Web兼容性)。許多ES2020中帶來(lái)的特性也依然會(huì)被?持。
        • 通過(guò)100%的ECMAScript Test Suite測(cè)試。
        • 可以將Javascript源編譯為沒(méi)有外部依賴(lài)的可執(zhí)??件。

        deno

        deno 是?類(lèi)類(lèi)似于 node.js 的 JS 運(yùn)?時(shí)環(huán)境,同時(shí)他 也是由 node.js 之???打造出來(lái)的,他和 node.js ? 有什么區(qū)別呢?

        • 相同點(diǎn):

          • deno 也是基于 V8 ,上層封裝?些系統(tǒng)級(jí)別的調(diào)?
          • 我們的 deno 應(yīng)?也可以使? JS 開(kāi)發(fā)
        • 不同點(diǎn):

          • deno 基于 rust 和 typescript 開(kāi)發(fā)?些上層模塊,所 以我們可以直接在 deno 應(yīng)?中書(shū)寫(xiě) ts
          • deno ?持從 url 加載模塊,同時(shí)?持 top level await 等特性

        sequelize ORM 框架

        幫助我們抹平了 底層數(shù)據(jù)庫(kù)的細(xì)節(jié),我們使?這類(lèi)框架,就能按照它的 語(yǔ)法進(jìn)?書(shū)寫(xiě),最終?成能夠應(yīng)?于各個(gè)平臺(tái)的 sql 語(yǔ)句。

        pm2 服務(wù)部署

        使? pm2 啟動(dòng)服務(wù)端、進(jìn)?運(yùn)維

        ????npm?install?-g?pm2
        ????pm2?start?ws-server.js?—name?my-server
        ????pm2?list
        ????pm2?monit
        ????pm2?logs?ws-server.js

        問(wèn)幾個(gè)問(wèn)題

        Q1:下面哪幾種寫(xiě)法可以正確導(dǎo)出(commonJS)

        ????module.exports='hello?word'?//√
        ????exports.key='hello?word'?//√
        ????exports='hello?word'?//×

        exports是module.exports值的引用,直接更改時(shí)引用地址進(jìn)行了改變,不會(huì)對(duì)module.exports產(chǎn)生影響

        Q2:自測(cè)一下

        ????console.log('script?start');
        ????
        ????setTimeout(function()?{
        ??????console.log('setTimeout');
        ????},?0);
        ????
        ????Promise.resolve().then(function()?{
        ??????console.log('promise1');
        ????}).then(function()?{
        ??????console.log('promise2');
        ????});
        ????console.log('script?end');

        script start->script end->promise1->promise2->setTimeout

        Q3:再測(cè)一下

        ????console.log('script?start')
        ????
        ????async?function?async1()?{
        ??????await?async2()
        ??????console.log('async1?end')
        ????}
        ????async?function?async2()?{
        ??????console.log('async2?end')?
        ????}
        ????async1()
        ????
        ????setTimeout(function()?{
        ??????console.log('setTimeout')
        ????},?0)
        ????
        ????new?Promise(resolve?=>?{
        ??????console.log('Promise')
        ??????resolve()
        ????})
        ??????.then(function()?{
        ????????console.log('promise1')
        ??????})
        ??????.then(function()?{
        ????????console.log('promise2')
        ??????})
        ????
        ????console.log('script?end')

        script start->async2 end->Promise->script end->async1 end->promise1->promise2->setTimeout

        巨人的肩膀

        • [npm發(fā)布包以及更新包還有需要注意的幾點(diǎn)問(wèn)題(這里以發(fā)布vue插件為例)][npm_vue]
        • [你好,JavaScript異步編程---- 理解JavaScript異步的美妙][JavaScript_---- _JavaScript]
        • [這一次,徹底弄懂 JavaScript 執(zhí)行機(jī)制][JavaScript]
        • [你不知道的 Event Loop][Event Loop]
        • [【THE LAST TIME】徹底吃透 JavaScript 執(zhí)行機(jī)制][THE LAST TIME_ JavaScript]
        • [深入理解 JavaScript Event Loop][JavaScript Event Loop]
        • [從event loop規(guī)范探究javaScript異步及瀏覽器更新渲染時(shí)機(jī)][event loop_javaScript]
        • [一次弄懂Event Loop(徹底解決此類(lèi)面試問(wèn)題)][Event Loop 1]
        • [瀏覽器與Node的事件循環(huán)(Event Loop)有何區(qū)別?][Node_Event Loop]**


        瀏覽 74
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            啊轻点灬太粗嗯太深了用力音频 | 攵女乱爱视频国语 | 久久久精品一品道久久 | 天天干夜夜操视频免费专区 | 人人操人人舔 | 天天澡天天狠天干天 | 免费污污污网站 | 四虎永久免费观看 | 91嫩草欧美久久久九九九 | 洪蓉全部裸体写真视频 |