<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                [TOC] # 分析工具0x 這里我們首先來介紹一款開源的Node.js性能分析工具[0x](https://github.com/davidmarkclements/0x), 借助它可以以火焰圖的形式發現你代碼中的性能瓶頸。 ## 使用方式 首先我們來模擬一個性能差的應用, 在getInitalProps方法中, 加入長循環。 ~~~ Page.getInitialProps = (ctx) => { for (let i = 0; i < 1000000; i++) { console.log('xx') } return Promise.resolve({ news: [{ id: '1', title: 'Racket v7.3 Release Notes' }, { id: '2', title: 'Free Dropbox Accounts Now Only Sync to Three Devices' }, { id: '3', title: 'Voynich Manuscript Decoded by Bristol Academic' }, { id: '4', title: 'Burger King to Deliver Whoppers to LA Drivers Stuck in Traffic' }, { id: '5', title: 'How much do YouTube celebrities charge to advertise your product? ' } ] }) } ~~~ 接著我們寫一個可以直接啟動我們應用的腳本文件, 不需要通過egg-bin的方式來啟動 ~~~ const Application = require('egg-core').EggCore const Router = require('koa-router') const { renderToStream } = require('ykfe-utils') const router = new Router() const config = require('./config/config.default') const app = new Application({ framework: false }) router.get('/', async (ctx) => { ctx.type = 'text/html' ctx.status = 200 const stream = await renderToStream(ctx, 'Page', config) ctx.body = stream }) app.use(router.routes()) app.ready(() => { app.listen(7001) console.log( `egg app start success. port 7001` ) }) ~~~ 接著我們用0x來檢測我們的應用 ~~~ npm install - g 0x 0x -o -- node start.js // -o選項讓0x來自動從瀏覽器中打開熱力圖 ab -n 100 -c 2 http://127.0.0.1:7001/ //用ab工具來向該應用發起100次請求,每次并發數為2 ~~~ ## 分析結果 ![](https://img.alicdn.com/tfs/TB1EdU3cMaH3KVjSZFjXXcFWpXa-2664-816.jpg)我們可以看到標紅的部分的調用棧, 首先是Page.server.js, 也就是我們服務端打包出的bundle文件, 在這個文件中調用了t.default, 也就是打包后的serverRender方法, 接著是調用了o.getInitialProps, 我們就可以很輕易的知道是這個方法里面出了問題, 它還可以更細致的告訴你是這個方法的哪一行出了問題, 這里是console.log的代碼塊出了問題。 # 壓力測試 ## 工具 * ab * ab -c10 -t15 -k 頁面地址 * webbench ## 性能指標 * QPS * 吞吐量 ![](https://img.kancloud.cn/04/13/041328195dd96b0f49787ecd88c747d8_1746x1668.png) ## 找到性能瓶頸 * top命令 * iostat 命令 # Node.js 性能分析 * Node.js profile * Chrome devtool * npm - clinic ## Chrome devtool ``` node --inspect-brk 文件入口 ``` ![](https://img.kancloud.cn/cf/93/cf9364a33ba570bb4ae4ed09345bc42c_704x190.png) <br> <br> ![](https://img.kancloud.cn/77/1f/771f2ee6b490330d370268cbd6939cf3_1182x694.png) <br> <br> # JavaScript 代碼性能優化 性能優化的準則 * 減少不必要的計算 * 空間換時間 Node.js HTTP 服務性能優化準則 * 提前計算:將計算從服務階段放到啟動階段 # 進程和子進程 ~~~ // const cp = require('child_process') const child_process = cp.fork(__dirname + '/child.js') child_process.send('hello') child_process.on('message', (data) => { console.log('子進程的消息', data) }) // child.js process.on('message', (data) => { process.send('hi', data) }) ~~~ 創建子線程,在Node 10版本中使用 Worker Thread # 利用多核進行多線程優化 ~~~ const cluster = require('cluster') const os = require('os') if (cluster.isMaster) { for (var i = 0; i < os.cpus().length / 2; i++) { cluster.fork() } } else { require('./app') } ~~~ # 進程守護 ~~~ /** * 簡單的進程守護器 */ const cluster = require('cluster'); if (cluster.isMaster) { for (let i = 0; i < require('os').cpus().length / 2; i++) { createWorker(); } // 退出進程5秒后,重新創建進程并進行心跳監控 cluster.on('exit', function () { setTimeout(() => { createWorker() }, 5000) }) function createWorker() { // 創建子進程并進行心跳監控 var worker = cluster.fork(); var missed = 0;// 沒有回應的ping次數 // 心跳 var timer = setInterval(function () { // 三次沒回應,殺之 if (missed == 3) { clearInterval(timer); console.log(worker.process.pid + ' has become a zombie!'); process.kill(worker.process.pid); return; } // 開始心跳 missed++; worker.send('ping#' + worker.process.pid); }, 10000); worker.on('message', function (msg) { // 確認心跳回應。 if (msg == 'pong#' + worker.process.pid) { missed--; } }); // 掛了就沒必要再進行心跳了 worker.on('exit', function () { clearInterval(timer); }); } } else { // 當進程出現會崩潰的錯誤 process.on('uncaughtException', function (err) { // 這里可以做寫日志的操作 console.log(err); // 退出進程 process.exit(1); }); // 回應心跳信息 process.on('message', function (msg) { if (msg == 'ping#' + process.pid) { process.send('pong#' + process.pid); } }); // 內存使用過多,自殺 if (process.memoryUsage().rss > 734003200) { process.exit(1); } require('./app') } ~~~ # 常見性能問題 ## 處理cpu密集型任務 在實際的開發中, 我相信大部分人都能夠輕易發現這種長循環的問題, 同時也可以看出, Node.js在處理cpu密集型的任務時確實不擅長, 當然也有辦法通過創建子進程或者線程的方式處理, 這里先不介紹了。 ## 請求數據超時 這里我們經常會遇到請求后端接口時響應時間過長,導致頁面的響應遲遲沒有返回。這里我們可以為所有的請求封裝一層自定義操作,例如設置超時時間,以及錯誤的catch處理。 ## 服務端生成的字符串size過大 我們注意到了我們在服務端將生成好的html字符串, 與獲取好的數據以window.\_\_initialData\_\_的方式返回給了客戶端, 那么一旦這塊數據size特別大達到700KB或者幾MB時, 隨著請求qps的增多, 我們很容易造成cpu飆升的現象。 ## 解決方式 ### 數據緩存 我們可以使用redis來作為儲存服務端數據的容器, 在實時性不是特別強的應用, 我們可以設置過期時間, 來讓服務端處理的邏輯減少很多 ### 過濾數據 我們可以只保留需要的字段, 例如我只需要當前視頻的標題信息以及演員信息字段, 而后端將視頻的幾十個字段信息都返回給你了, 這時候你可以定義一個filter方法來過濾數據 ### 服務端只渲染部分模塊 我們可以將頁面分為服務端和客戶端渲染兩部分, 讓服務端只專注于首屏渲染, 以下是一種實現方式, 我們以移動端豎版的feed來舉例。 ~~~ class Page { componentWillMount() { // 首先獲取到當前的需要渲染的抽屜 const moduleList = this.props.moduleList // 定義兩個數組,分別存放服務端需要渲染的抽屜以及客戶端需要渲染的抽屜 let serverModuleList = [] let clientModuleList = [] if (moduleList.length > 5) { // 如果當前抽屜的數量大于5個 // 將前5個抽屜賦值給服務端需要渲染的抽屜,后面的抽屜賦值給客戶端需要渲染的抽屜 serverModuleList = moduleList.slice(0, 5) clientModuleList = moduleList.slice(5, moduleList.length) this.setState({ clientModuleList: clientModuleList }) } else { // 如果抽屜數量小于5個,全部由服務端渲染 serverModuleList = moduleList } this.setState({ // 首先用serverModuleList作為state,來讓服務端只渲染serverModuleList包含的抽屜 moduleList: serverModuleList }) } componentDidMount () { if (this.state.clientModuleList.length !== 0) { // 如果存在客戶端渲染的抽屜,將其與當前的moduleList即serverModuleList組合成一個完整的頁面包含的抽屜 // 當state更新時,觸發頁面的重新render來觸發客戶端渲染 this.setState({ moduleList: this.state.moduleList.concat(this.state.clientModuleList) }) } } render () { return ( <div> { // 這里我們還可以結合懶加載來進一步提升首屏性能 this.state.moduleList.map((item, index) => <Lazyload key={`com${index}`}><Component data={item} /></Lazyload>) } </div> ) } } ~~~ ### 打底數據 當我們服務端渲染出現錯誤時候,例如在服務端代碼訪問了瀏覽器對象,我們總不能讓用戶看到白屏的頁面。這里我們可以使用兩種方式來解決。 * 降級為客戶端渲染,我們在config配置中提供了當前的渲染模式,當你的應用出現問題而又無法立即解決時,可以先降級為客戶端渲染,這樣即使你某個模塊出了問題,其他的模塊還能夠展示 * 使用mock數據,當頁面出現暫時無法修復的錯誤時,我們可以直接在服務端返回一個我們事先準備好的mock的完整html數據返回給客戶端
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看