成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

[email protected] 源碼解讀

yearsj / 3445人閱讀

摘要:如果此時(shí)我們不想把文件輸出到內(nèi)存里,可以通過修改的源代碼來實(shí)現(xiàn)。服務(wù)啟動(dòng)成功。。。根據(jù)請(qǐng)求的,拼接出

? webpack-dev-middleware 是express的一個(gè)中間件,它的主要作用是以監(jiān)聽模式啟動(dòng)webpack,將webpack編譯后的文件輸出到內(nèi)存里,然后將內(nèi)存的文件輸出到epxress服務(wù)器上;下面通過一張圖片來看一下它的工作原理:

了解了它的工作原理以后我們通過一個(gè)例子進(jìn)行實(shí)操一下。

demo1:初始化webpack-dev-middleware中間件,啟動(dòng)webpack監(jiān)聽模式編譯,返回express中間件函數(shù)

// src/app.js
console.log("App.js");
document.write("webpack-dev-middleware");
// demo1/index.js
const path = require("path");
const express = require("express");
const webpack = require("webpack");
const webpackDevMiddleware = require("webpack-dev-middleware");     // webpack開發(fā)中間件
const HtmlWebpackPlugin = require("html-webpack-plugin");           // webpack插件:根據(jù)模版生成html,并且自動(dòng)注入引用webpack編譯出來的css和js文件

/**
 * 創(chuàng)建webpack編譯器
 */
const comoiler = webpack({  // webpack配置
    entry: path.resolve(__dirname, "src/app.js"),       // 入口文件
    output: {                                           // 輸出配置
        path: path.resolve(__dirname, "dist"),          // 輸出路徑
        filename: "bundle.[hash].js"                    // 輸出文件
    },
    plugins: [                                          // 插件
        new HtmlWebpackPlugin({                         // 根據(jù)模版自動(dòng)生成html文件插件,并將webpack打包輸出的js文件注入到html文件中
            title: "webpack-dev-middleware"
        })
    ]
});

/**
 * 執(zhí)行webpack-dev-middleware初始化函數(shù),返回express中間件函數(shù)
 * 這個(gè)函數(shù)內(nèi)部以監(jiān)聽模式啟動(dòng)了webpack編譯,相當(dāng)于執(zhí)行cli的: webpack --watch命令
 * 也就是說執(zhí)行到這一步,就已經(jīng)啟動(dòng)了webpack的監(jiān)聽模式編譯了,代碼執(zhí)行到這里可以看到控制臺(tái)已經(jīng)輸出了webpack編譯成功的相關(guān)日志了
 * 由于webpack-dev-middleware中間件內(nèi)部使用memory-fs替換了compiler的outputFileSystem對(duì)象,將webpack打包編譯的文件都輸出到內(nèi)存中
 * 所以磁盤上看不到任何webpack編譯輸出的文件
 */
const webpackDevMiddlewareInstance = webpackDevMiddleware(comoiler,{
    reportTime: true,           // webpack狀態(tài)日志輸出帶上時(shí)間前綴
    stats: {
        colors: true,           // webpack編譯輸出日志帶上顏色,相當(dāng)于命令行 webpack --colors
        process: true
    }
});

運(yùn)行結(jié)果:

源碼鏈接:https://github.com/Jameswain/...

? 通過上述例子的運(yùn)行結(jié)果,我們可以發(fā)現(xiàn)webpack-dev-middleware實(shí)際上是一個(gè)函數(shù),通過執(zhí)行它會(huì)返回一個(gè)express風(fēng)格的中間件函數(shù),并且會(huì)以監(jiān)聽模式啟動(dòng)webpack編譯。由于webpack-dev-middleware中間件內(nèi)部使用memory-fs替換了compiler的outputFileSystem對(duì)象,將webpack打包編譯的文件都輸出到內(nèi)存中,所以雖然我們看到控制臺(tái)上有webpack編譯成功的日志,但是并沒有看到任何的輸出文件,就是這個(gè)原因,因?yàn)檫@些文件在內(nèi)存里。

? 如果此時(shí)我們不想把文件輸出到內(nèi)存里,可以通過修改webpack-dev-middleware的源代碼來實(shí)現(xiàn)。打開node_modules/webpack-dev-middleware/lib/Shared.js文件,將該文件的231行注視掉后,重新運(yùn)行 node demo1/index.js 即可看到文件被輸出到demo1/dist文件夾中。

? 問:為什么webpack-dev-middleware要將webpack打包后的文件輸出到內(nèi)存中,而不是直接到磁盤上呢?

? 答:速度,因?yàn)镮O操作是非常耗資源時(shí)間的,直接在內(nèi)存里操作會(huì)比磁盤操作會(huì)更加快速和高效。因?yàn)榧词故莣ebpack把文件輸出到磁盤,要將磁盤上到文件通過一個(gè)服務(wù)輸出到瀏覽器,也是需要將磁盤的文件讀取到內(nèi)存里,然后在通過流進(jìn)行輸出,然后瀏覽器上才能看到,所以中間件這么做其實(shí)還是省了一步讀取磁盤文件的操作。

? 下面通過一個(gè)例子演示一下如何將本地磁盤上的文件通過Express服務(wù)輸出到response,在瀏覽器上進(jìn)行訪問:

//demo3/app.js
const express = require("express");
const path = require("path");
const fs = require("fs");
const app = express();

// 讀取index.html文件
const htmlIndex = fs.readFileSync(path.resolve(__dirname,"index.html"));
// 讀取圖片
const img = fs.readFileSync(path.resolve(__dirname, "node.jpg"));

app.use((req, res, next) => {
    console.log(req.url)
    if (req.url === "/" || req.url === "/index.html") {
        res.setHeader("Content-Type", "text/html;charset=UTF-8");
        res.setHeader("Content-Length", htmlIndex.length);
        res.send(htmlIndex);    // 傳送HTTP響應(yīng)
        // res.end();           // 此方法向服務(wù)器發(fā)出信號(hào),表明已發(fā)送所有響應(yīng)頭和主體,該服務(wù)器應(yīng)該視為此消息已完成。 必須在每個(gè)響應(yīng)上調(diào)用此 response.end() 方法。
        // res.sendFile(path.resolve(__dirname, "index.html"));    //傳送指定路徑的文件 -會(huì)自動(dòng)根據(jù)文件extension設(shè)定Content-Type
    } else if (req.url === "/node.jpg") {
        res.end(img);   // 此方法向服務(wù)器發(fā)出信號(hào),表明已發(fā)送所有響應(yīng)頭和主體,該服務(wù)器應(yīng)該視為此消息已完成。 必須在每個(gè)響應(yīng)上調(diào)用此 response.end() 方法。
    }
});

app.listen(3000, () => console.log("express 服務(wù)啟動(dòng)成功。。。"));

//瀏覽器訪問:http://localhost:3000/node.jpg
//瀏覽器訪問:http://localhost:3000/

項(xiàng)目目錄:

運(yùn)行結(jié)果:

通過上述代碼我們可以看出不管是輸出html文件還是圖片文件都是需要先將這些文件讀取到內(nèi)存里,然后才能輸出到response上。

?

middleware.js

? 下面我們就來看看webpack-dev-middleware這個(gè)函數(shù)內(nèi)部是如何實(shí)現(xiàn)的,它的運(yùn)行原理是什么?個(gè)人感覺讀源碼最主要的就是基礎(chǔ) + 耐心 + 流程

? 首先打開node_modules/webpack-dev-middleware/middleware.js文件,注意版本號(hào),我這份代碼的版本號(hào)是[email protected]。

? middleware.js文件就是webpack-dev-middleware的入口文件,它主要做以下幾件事情:

? 1、記錄compiler對(duì)象和中間件配置

? 2、創(chuàng)建webpack操作對(duì)象shared

? 3、創(chuàng)建中間件函數(shù)webpackDevMiddleware

? 4、將webpack的一些常用操作函數(shù)暴露到中間件函數(shù)上,供外部直接調(diào)用

? 5、返回中間件函數(shù)

Shared.js

這個(gè)文件對(duì)webpack的compiler這個(gè)對(duì)象進(jìn)行封裝操作,我們大概先來看看這個(gè)文件主要做了哪些事情:

首先設(shè)置中間件的一些默認(rèn)選項(xiàng)配置

使用memory-fs對(duì)象替換掉compiler的文件系統(tǒng)對(duì)象,讓webpack編譯后的文件輸出到內(nèi)存中

監(jiān)聽webpack的鉤子函數(shù)

invalid:監(jiān)聽模式下,文件發(fā)生變化時(shí)調(diào)用,同時(shí)會(huì)傳入2個(gè)參數(shù),分別是文件名和時(shí)間戳

watch-run:監(jiān)聽模式下,一個(gè)新的編譯觸發(fā)之后,完成編譯之前調(diào)用

done:編譯完成時(shí)調(diào)用,并傳入webpack編譯日志對(duì)象stats

run:在開始讀取記錄之前調(diào)用,只有調(diào)用compiler.run()函數(shù)時(shí)才會(huì)觸發(fā)該鉤子函數(shù)

以觀察者模式啟動(dòng)webpack編譯

返回share對(duì)象,該對(duì)象封裝了很多關(guān)于compiler的操作函數(shù)

通過上面的截圖我們大概知道了Shared.js文件的運(yùn)行流程,下面我們?cè)賮砜纯此恍┍容^重要的細(xì)節(jié)。

share.setOptions 設(shè)置中間件的默認(rèn)配置

share.setFs(context.compiler) 設(shè)置compiler的文件操作對(duì)象

share.startWatch() 以觀察模式啟動(dòng)webpack

compiler.watch(watchOptions, callback) 這個(gè)函數(shù)表示以監(jiān)聽模式啟動(dòng)webpack并返回一個(gè)watching對(duì)象,這里特別需要注意的是當(dāng)調(diào)用compiler.watch函數(shù)時(shí)會(huì)立即執(zhí)行watch-run這個(gè)鉤子回調(diào)函數(shù),直到這個(gè)鉤子回調(diào)函數(shù)執(zhí)行完畢后,才會(huì)返回watching對(duì)象。

share.compilerDone(stats) webpack編譯完成回調(diào)處理函數(shù)

當(dāng)webpack的一個(gè)編譯完成時(shí)會(huì)進(jìn)入done鉤子回調(diào)函數(shù),然后調(diào)用compilerDone函數(shù),這個(gè)函數(shù)內(nèi)部首先將context.state設(shè)置為true表示webpack編譯完成,并記錄webpack的統(tǒng)計(jì)信息對(duì)象stats,然后將webpack日志輸出操作和回調(diào)函數(shù)執(zhí)行都放到process.nextTick()任務(wù)隊(duì)列執(zhí)行,就是等主邏輯所有的代碼執(zhí)行完畢后才進(jìn)行webpack的日志輸出和中間件回調(diào)函數(shù)的執(zhí)行。

context.options.reporter (share.defaultReporter) webpack默認(rèn)日志輸出函數(shù)

context.options.reporter 和 share.defaultReporter 指向的都是同一個(gè)函數(shù)

? 通過代碼我們可以看出這個(gè)函數(shù)內(nèi)部首先是要判斷一下state這個(gè)狀態(tài),false表示webpack處于編譯中,則直接輸出 webpack: Compiling...。true:則表示webpack編譯完成,則需要判斷webpack-dev-middleware這個(gè)中間件都兩個(gè)配置,noInfo和quiet,noInfo如果是為true則只輸出錯(cuò)誤和警告,quiet為true則不輸出任何內(nèi)容,默認(rèn)這倆選項(xiàng)都是false,這時(shí)候會(huì)判斷webpack編譯成功后返回的stats對(duì)象里有沒有錯(cuò)誤和警告,有錯(cuò)誤或警告就輸出錯(cuò)誤和警告,沒有則輸出webpack的編譯日志,并且使用webpack-dev-middleware的options.stats配置項(xiàng)作為webpack日志輸出配置,更多webpack日志輸出配置選項(xiàng)見:https://www.webpackjs.com/con...

handleCompilerCallback() - watch回調(diào)函數(shù)

這個(gè)是watch回調(diào)函數(shù),它是在compiler.plugin("done")鉤子函數(shù)執(zhí)行完畢之后執(zhí)行,它有兩個(gè)參數(shù),一個(gè)是錯(cuò)誤信息,一個(gè)是webpack編譯成功的統(tǒng)計(jì)信息對(duì)象stats,可以看到這個(gè)回調(diào)函數(shù)內(nèi)部只做錯(cuò)誤信息的輸出。

webpack watch模式鉤子函數(shù)執(zhí)行流程圖

使用webpack-dev-middleware中間件

? 之前我介紹的都是webpack-dev-middleware中間件初始化階段主要做了什么事情,而且我的第一個(gè)代碼例子里也只是調(diào)用了webpack-dev-middleware中間件的初始化函數(shù)而已,并沒有和express結(jié)合使用,當(dāng)時(shí)這么做的主要是為了說明這個(gè)中間件的初始化階段的運(yùn)行機(jī)制,下面我們通過一個(gè)完整一點(diǎn)的例子說明webpack-dev-middleware中間件如何和express進(jìn)行結(jié)合使用以及它的運(yùn)行流程和原理。

// demo2/index.js
const path = require("path");
const express = require("express");
const webpack = require("webpack");
const webpackDevMiddleware = require("webpack-dev-middleware");
const HtmlWebpackPlugin = require("html-webpack-plugin");

// 創(chuàng)建webpack編譯器
const compiler = webpack({
    entry: path.resolve(__dirname, "src/app.js"),
    output: {
        path: path.resolve(__dirname, "dist"),
        filename: "bundle.[hash].js"
    },
    plugins: [
        new HtmlWebpackPlugin({
            title: "webpack-dev-middleware"
        })
    ]
});

// webpack開發(fā)中間件:其實(shí)這個(gè)中間件函數(shù)執(zhí)行完成時(shí),中間件內(nèi)部就會(huì)執(zhí)行webpack的watch函數(shù),啟動(dòng)webpack的監(jiān)聽模式,相當(dāng)于執(zhí)行cli的: webpack --watch命令
const webpackDevMiddlewareInstance = webpackDevMiddleware(compiler, {
    reportTime: true,           // webpack狀態(tài)日志輸出帶上時(shí)間前綴
    stats: {
        colors: true,           // webpack編譯輸出日志帶上顏色,相當(dāng)于命令行 webpack --colors
        process: true
    },
    // noInfo: true,            // 不輸出任何webpack編譯日志(只有警告和錯(cuò)誤)
    // quiet: true,             // 不向控制臺(tái)顯示任何內(nèi)容
    // reporter: function (context) {   // 提供自定義報(bào)告器以更改webpack日志的輸出方式。
    //     console.log(context.stats.toString(context.options.stats))
    // },
});

/**
 * webpack第一次編譯完成并且輸出編譯日志后調(diào)用
 * 之后監(jiān)聽到文件變化重新編譯不會(huì)再執(zhí)行此函數(shù)
 */
webpackDevMiddlewareInstance.waitUntilValid(stats => {
    console.log("webpack第一次編譯成功回調(diào)函數(shù)");
});

// 創(chuàng)建express對(duì)象
const app = express();
app.use(webpackDevMiddlewareInstance);      // 使用webpack-dev-middleware中間件,每一個(gè)web請(qǐng)求都會(huì)進(jìn)入該中間件函數(shù)
app.listen(3000, () => console.log("啟動(dòng)express服務(wù)..."));  // 啟動(dòng)express服務(wù)器在3000端口上

// for (let i = 0; i < 10000022220; i++) {}    // 會(huì)阻塞webpack的編譯操作

? 源碼地址:https://github.com/Jameswain/...

? 通過app.use進(jìn)行使用中間件,然后我們通過在瀏覽器訪問localhost:3000,然后就可以看到效果了,此時(shí)任何一個(gè)web請(qǐng)求都會(huì)執(zhí)行webpack-dev-middleware的中間件函數(shù),下面我們來看看這個(gè)中間件函數(shù)內(nèi)部是如何實(shí)現(xiàn)的,到底做了哪些事情。

? 1、我們先通過一個(gè)流程圖看一下上面這段代碼首次執(zhí)行webpack-dev-middleware的內(nèi)部運(yùn)行流程

?

? 2、middleware.js文件中的webpackDevMiddleware函數(shù)代碼解析

// webpack-dev-middleware 中間件函數(shù),每一個(gè)http請(qǐng)求都會(huì)進(jìn)入次函數(shù)
    function webpackDevMiddleware(req, res, next) {
        /**
         * 執(zhí)行下一個(gè)中間件
         */
        function goNext() {
            // 如果不是服務(wù)器端渲染,則直接執(zhí)行下一個(gè)中間件函數(shù)
            if(!context.options.serverSideRender) return next();
            return new Promise(function(resolve) {
                shared.ready(function() {
                    res.locals.webpackStats = context.webpackStats;
                    resolve(next());
                }, req);
            });
        }

        // 如果不是GET請(qǐng)求,則直接調(diào)用下一個(gè)中間件并返回退出函數(shù)
        if(req.method !== "GET") {
            return goNext();
        }

        // 根據(jù)請(qǐng)求的URL獲取webpack編譯輸出文件的絕對(duì)路徑;例如:req.url="/bundle.492db0756b0d8df3e6dd.js" 獲取到的filename就是"/Users/jameswain/WORK/blog/demo2/dist/bundle.492db0756b0d8df3e6dd.js"
        // 可以看到其實(shí)就是webpack編譯輸出文件的絕對(duì)路徑和名稱
        var filename = getFilenameFromUrl(context.options.publicPath, context.compiler, req.url);
        if(filename === false) return goNext();

        return new Promise(function(resolve) {
            shared.handleRequest(filename, processRequest, req);
            function processRequest(stats) {
                try {
                    var stat = context.fs.statSync(filename);
                    // 處理當(dāng)前請(qǐng)求是 / 的情況
                    if(!stat.isFile()) {
                        if(stat.isDirectory()) {
                            // 如果請(qǐng)求的URL是/,則將它的文件設(shè)置為中間件配置的index選項(xiàng)
                            var index = context.options.index;
                            // 如果中間件沒有設(shè)置index選項(xiàng),則默認(rèn)設(shè)置為index.html
                            if(index === undefined || index === true) {
                                index = "index.html";
                            } else if(!index) {
                                throw "next";
                            }
                            // 將webpack的輸出目錄outputPath和index.html拼接起來
                            filename = pathJoin(filename, index);
                            stat = context.fs.statSync(filename);
                            if(!stat.isFile()) throw "next";
                        } else {
                            throw "next";
                        }
                    }
                } catch(e) {
                    return resolve(goNext());
                }

                // server content  服務(wù)器內(nèi)容
                // 讀取文件內(nèi)容
                var content = context.fs.readFileSync(filename);
                // console.log(content.toString())  //輸出文件內(nèi)容
                // 處理可接受數(shù)據(jù)范圍的請(qǐng)求頭
                content = shared.handleRangeHeaders(content, req, res);
                // 獲取文件的mime類型
                var contentType = mime.lookup(filename);
                // do not add charset to WebAssembly files, otherwise compileStreaming will fail in the client
                // 不要將charset添加到WebAssembly文件中,否則編譯流將在客戶端失敗
                if(!/.wasm$/.test(filename)) {
                    contentType += "; charset=UTF-8";
                }
                res.setHeader("Content-Type", contentType);
                res.setHeader("Content-Length", content.length);
                // 中間件自定義請(qǐng)求頭配置,如果中間件有配置,則循環(huán)設(shè)置這些請(qǐng)求頭
                if(context.options.headers) {
                    for(var name in context.options.headers) {
                        res.setHeader(name, context.options.headers[name]);
                    }
                }
                // Express automatically sets the statusCode to 200, but not all servers do (Koa).
                // Express自動(dòng)將statusCode設(shè)置為200,但不是所有服務(wù)器都這樣做(Koa)。
                res.statusCode = res.statusCode || 200;
                // 將請(qǐng)求的文件或數(shù)據(jù)內(nèi)容輸出到客戶端(瀏覽器)
                if(res.send) res.send(content);
                else res.end(content);
                resolve();
            }
        });
    }

? 這是webpack-dev-middleware中間件的源代碼,我加了一些注釋和個(gè)人見解說明這個(gè)中間件內(nèi)部的具體操作,這里我簡(jiǎn)單總結(jié)一下這個(gè)中間件函數(shù)主要做了哪些事情:

首先判斷如果不是GET請(qǐng)求,則調(diào)用下一個(gè)中間件函數(shù),并退出當(dāng)前中間件函數(shù)。

根據(jù)請(qǐng)求的URL,拼接出該資源在webpack輸出目錄的絕對(duì)路徑。例如:請(qǐng)求的URL為“/bundle.js”,那么在我電腦拼接出的絕對(duì)路徑就為"/Users/jameswain/WORK/blog/demo2/dist/bundle.js",如果請(qǐng)求的URL為/,設(shè)置文件為index.html

讀取請(qǐng)求文件的內(nèi)容,是一個(gè)Buffer類型,可以立即為流

判斷客戶端是否設(shè)置了range請(qǐng)求頭,如果設(shè)置了,則需要對(duì)內(nèi)容進(jìn)行截取限制在指定范圍之內(nèi)。

獲取請(qǐng)求文件的mime類型

設(shè)置請(qǐng)求頭Content-Type和Content-Length,循環(huán)設(shè)置中間件配置的自定義請(qǐng)求頭

設(shè)置狀態(tài)碼為200

將文件內(nèi)容輸出到客戶端

? 下面通過一個(gè)流程圖看一下這個(gè)中間件函數(shù)的執(zhí)行流程:

總結(jié)

? webpack-dev-middleware這個(gè)中間件內(nèi)部其實(shí)主就是做了兩件事,第一就是在中間件函數(shù)初始化時(shí),修改webpack的文件操作對(duì)象,讓webpack編譯后的文件輸出到內(nèi)存里,以監(jiān)聽模式啟動(dòng)webpack。第二就是當(dāng)有http get請(qǐng)求過來時(shí),中間件函數(shù)內(nèi)部讀取webpack輸出到內(nèi)存里的文件,然后輸出到response上,這時(shí)候?yàn)g覽器拿到的就是webpack編譯后的資源文件了。

? 最后給出本文所有相關(guān)源代碼的地址:https://github.com/Jameswain/...

? 聲明:本文純屬個(gè)人閱讀[email protected]源碼的一些個(gè)人理解和感悟,由于本人技術(shù)水平有限,如有錯(cuò)誤還望各位大神批評(píng)指正。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/102835.html

相關(guān)文章

  • React 源碼深度解讀(三):首次 DOM 元素渲染 - Part 3

    摘要:在學(xué)習(xí)源碼的過程中,給我?guī)椭畲蟮木褪沁@個(gè)系列文章,于是決定基于這個(gè)系列文章談一下自己的理解。到此為止,首次渲染就完成啦總結(jié)從啟動(dòng)到元素渲染到頁面,并不像看起來這么簡(jiǎn)單,中間經(jīng)歷了復(fù)雜的層級(jí)調(diào)用。 前言 React 是一個(gè)十分龐大的庫,由于要同時(shí)考慮 ReactDom 和 ReactNative ,還有服務(wù)器渲染等,導(dǎo)致其代碼抽象化程度很高,嵌套層級(jí)非常深,閱讀其源碼是一個(gè)非常艱辛的過...

    U2FsdGVkX1x 評(píng)論0 收藏0
  • React 源碼深度解讀(六):依賴注入

    摘要:依賴注入和控制反轉(zhuǎn),這兩個(gè)詞經(jīng)常一起出現(xiàn)。一句話表述他們之間的關(guān)系依賴注入是控制反轉(zhuǎn)的一種實(shí)現(xiàn)方式。而兩者有大量的代碼都是可以共享的,這就是依賴注入的使用場(chǎng)景了。下一步就是創(chuàng)建具體的依賴內(nèi)容,然后注入到需要的地方這里的等于這個(gè)對(duì)象。 前言 React 是一個(gè)十分龐大的庫,由于要同時(shí)考慮 ReactDom 和 ReactNative ,還有服務(wù)器渲染等,導(dǎo)致其代碼抽象化程度很高,嵌套層級(jí)...

    glumes 評(píng)論0 收藏0
  • 來一打前端博客壓壓驚

    前言 本文所有內(nèi)容全部發(fā)布再個(gè)人博客主頁 https://github.com/muwoo/blogs歡迎訂閱。不過最近因?yàn)槭虑楸容^多,有一段時(shí)間沒有更新了,后面打算繼續(xù)不斷學(xué)習(xí)更新,歡迎小伙伴一起溝通交流~ 最近更新 前端單測(cè)的那些事 基于virtual dom 的canvas渲染 js Event loop 機(jī)制簡(jiǎn)介 axios 核心源碼實(shí)現(xiàn)原理 JS 數(shù)據(jù)類型、賦值、深拷貝和淺拷貝 j...

    wangbinke 評(píng)論0 收藏0
  • 來一打前端博客壓壓驚

    前言 本文所有內(nèi)容全部發(fā)布再個(gè)人博客主頁 https://github.com/muwoo/blogs歡迎訂閱。不過最近因?yàn)槭虑楸容^多,有一段時(shí)間沒有更新了,后面打算繼續(xù)不斷學(xué)習(xí)更新,歡迎小伙伴一起溝通交流~ 最近更新 前端單測(cè)的那些事 基于virtual dom 的canvas渲染 js Event loop 機(jī)制簡(jiǎn)介 axios 核心源碼實(shí)現(xiàn)原理 JS 數(shù)據(jù)類型、賦值、深拷貝和淺拷貝 j...

    villainhr 評(píng)論0 收藏0
  • 來一打前端博客壓壓驚

    前言 本文所有內(nèi)容全部發(fā)布再個(gè)人博客主頁 https://github.com/muwoo/blogs歡迎訂閱。不過最近因?yàn)槭虑楸容^多,有一段時(shí)間沒有更新了,后面打算繼續(xù)不斷學(xué)習(xí)更新,歡迎小伙伴一起溝通交流~ 最近更新 前端單測(cè)的那些事 基于virtual dom 的canvas渲染 js Event loop 機(jī)制簡(jiǎn)介 axios 核心源碼實(shí)現(xiàn)原理 JS 數(shù)據(jù)類型、賦值、深拷貝和淺拷貝 j...

    xiaoqibTn 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<