国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

寫一個 JS 調用棧可視化工具 hound-trace

solocoder / 3211人閱讀

摘要:背景最近在分析一些框架源碼,在寫筆記的時候,一些函數(shù)的調用棧希望用流程圖的形式記錄下來,打開就是一頓操作,畫了幾個調用棧之后,感覺很麻煩。

背景

最近在分析一些框架源碼,在寫筆記的時候,一些函數(shù)的調用棧希望用流程圖的形式記錄下來,打開 http://draw.io 就是一頓操作,畫了幾個調用棧之后,感覺很麻煩。于是蹲在廁所里的我開始思考了,調用棧既然可以用 console.trace() 打印出來,那是不是也可以把數(shù)據(jù)記錄下來直接畫出流程圖來?

當然我從不喜歡造輪子,首先熟練的打開 google 操作一波,發(fā)現(xiàn)地球之大,竟然沒有我想要的工具?沒有 JS 調用棧可視化工具?怎么辦?在繼續(xù)用 draw.io 手畫和自己造輪子之間我陷入了深思。

當然我最后選擇了造輪子,不然就沒有這篇文章了。

輪子長這樣 —> hound-trace <--

比如說有這樣一份代碼:

// 輪子
import houndTrace from "hound-trace-ui";

function f() {}

function e() {}

function d() { f() }

const b = () => { d(); e() };

const c = function () { d() };

function a() { b(); c() }

houndTrace.start();
a();
houndTrace.end();

可視化輸出:

造輪子的過程

### 首先要取個酷炫的名字

代碼寫的好不好,工具好不好用,不重要,一定要有酷炫的名字,那就是 hound-trace ,看這個谷歌翻譯出來的名字多么清新脫俗,光芒四射。

怎么去拿調用棧信息?

首先想到的是能不能在函數(shù)調用前后做點什么?作為 21 世紀的程序員,下手前當然是先 googlestackoverflow 一波,看看能不能輕輕松松當個搬運工。逛了半天,靠譜的答案似乎有這些:

// 偷天換日大法
var old = UIIntentionalStream.instance.loadOlderPosts;
UIIntentionalStream.instance.loadOlderPosts = function() {
    // hook before call
    old();
    // hook after call
};


// 原型拓展大法
Function.prototype.before = function (callback) {
    var that = this;
    return (function() {
        callback.apply(this, arguments);
        return (that.apply(this, arguments));
    });
}

Function.prototype.after = function (callback) {
    var that = this;
    return (function() {
        var result = that.apply(this, arguments);
        callback.apply(this, arguments);
        return (result);
    });
}

var both = test.before(function(a) {
    console.log("Before. Parameter = ", a);
}).after(function(a) {
    console.log("After. Parameter = ", a);
});
both(17);

看起來不錯,可是這,我要是看個 react 源碼,想拿到調用棧信息。函數(shù)調用豈不都要重寫個遍?不靠譜,還不如去手畫呢。

找啊找啊找,靈光一閃?AST。運行的時候不行,直接改代碼不就完了。就這么干?于是就寫了個 babel 插件,在代碼里下點毒。babel-plugin-hound-trace 這個插件干啥呢?

// ...
module.exports = function (babel) {

    return {
        visitor: {
              // 在我們的代碼里面遇到函數(shù)聲明語句,函數(shù)表達式,箭頭函數(shù)表達式的時候
            // 該插件會注入一些代碼
            FunctionDeclaration: (path) => {
                // ...    
            },
            FunctionExpression: expressionHandle.bind(null, babel),
            ArrowFunctionExpression: expressionHandle.bind(null, babel)
        }
    };
};
// ...

比如源碼里的函數(shù)如下:

function test(a, b, c) {
    const cj = "cj";
}

下毒之后(經(jīng)過這個插件處理之后):

function test(a, b, c) {
  let __traceParent__ = window.__traceParent__;
  let __traceOldParent__ = __traceParent__;

  if (window.__trace__) {
    if (!__traceParent__.next) {
      __traceParent__.next = [];
    }

    const current = {
      name: "test",
      params: ["a", "b", "c"]
    };

    __traceParent__.next.push(current);

    window.__traceParent__ = current;
  }

  const cj = "cj";
  window.__traceParent__ = __traceOldParent__;
}

注入的代碼比較奇怪,因為實現(xiàn)的思路是借助 window 上的全局變量來做這個事情,所以看起來奇怪。(暫時還沒想其它好方法)

注入了代碼之后就簡單了 ,可以看到代碼里注入了 window.__trace__ 這個變量用于是否記錄該函數(shù),所以 hound-trace 包的代碼就自然出來了:

let trace = false;

// 開始記錄調用棧
function __NoTraceHook__start() {
    if (trace) { return }

    window.__trace__ = trace = true;

    window.__traceParent__ = {};
}

// 結束記錄調用棧
function __NoTraceHook__end(callback) {
    if (!trace) { return }

    window.__trace__ = trace = false;

    callback && callback(window.__traceParent__);
}

export default {
    start: __NoTraceHook__start,
    end: __NoTraceHook__end
};

到這里,就差可視化渲染了,考慮到 UI 層是比較個性的,所以又拆了個包出來 hound-trace-ui 底層調用 hound-trace 的 API ,這樣以后就能隨意加皮膚了。

hound-trace-ui 其實很簡單,就是在 __NoTraceHook__end 的回調里可以拿到調用棧的數(shù)據(jù),然后怎么用這個數(shù)據(jù)就隨意了,這個包里使用的是 mermaid 做可視化(因為簡單):

// 調用 hound-trace 包代碼
import houndTrace from "../../hound-trace/src/index";
// 渲染數(shù)據(jù)邏輯
import renderCallStack from "./renderCallStack";

import "./index.css";


function start() {
    houndTrace.start();
}

// 包裝底層 API
function end() {
    houndTrace.end(callStack => {
        setTimeout(() => {
              // 調用 mermaid 包渲染數(shù)據(jù)
            renderCallStack(callStack);
        }, 14);
    });
}

export default {
    start,
    end,
    endAndRenderCallStack: end
};

好吧,就這樣世界上又多了一個輪子。

感興趣的可以去 star ,當然更希望大家給出奇淫技巧一起完善。—> hound-trace <--

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

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/106801.html

相關文章

  • 「全初探」- Mongoose的簡單使用

    摘要:下載依賴包完成項目創(chuàng)建,項目結構連接數(shù)據(jù)庫在根目錄下創(chuàng)建,輸入以下代碼,監(jiān)聽的幾個事件,如果以上操作都沒錯的話,那么就會監(jiān)聽第一個事件事件,表示連接數(shù)據(jù)庫成功,在最后,我們導出對象,以供其他模塊使用。 一、準備工作 1. 啟動mongo數(shù)據(jù)庫 關于下載安裝啟動數(shù)據(jù)庫我這里就不做過多解釋,谷歌下會有很多教程,啟動成功后的命令窗如下所示: showImg(https://segmentfa...

    vboy1010 評論0 收藏0
  • Node.js 究竟是什么?

    摘要:在回調隊列中,函數(shù)等待調用棧為空,因為每個語句都執(zhí)行一次。最后一個運行,并且從調用棧中彈出。它將回調以先進先出順序移動到調用棧并執(zhí)行。 翻譯:瘋狂的技術宅原文: https://medium.freecodecamp.o... 本文首發(fā)微信公眾號:前端先鋒歡迎關注,每天都給你推送新鮮的前端技術文章 Node.js 是一個 JavaScript 運行時環(huán)境。聽起來還不錯,不過這究竟...

    yeyan1996 評論0 收藏0
  • PyCon China 深圳站精彩回顧(附PPT及視頻)

    摘要:月日,第六屆大會在深圳召開。這是這次大會的第二站活動,第一站已在上海成功舉辦。深圳站視頻及,請在公眾號后臺回復,獲取分享鏈接。據(jù)介紹,目前支持多種開發(fā)庫,如內置和等。該協(xié)議的推出,是為了統(tǒng)一標準,提高效率。 本文為 PyChina 和「編程派」聯(lián)合首發(fā),作者為 EarlGrey。「編程派」是一個專注 Python 學習交流的微信公眾號。 9 月 25 日,第六屆 PyCon China...

    lykops 評論0 收藏0
  • JavaScript引擎是如何工作的?從調用到Promise你需要知道的一切

    摘要:最受歡迎的引擎是,在和中使用,用于,以及所使用的。單線程的我們說是單線程的,因為有一個調用棧處理我們的函數(shù)。也就是說,如果有其他函數(shù)等待執(zhí)行,函數(shù)是不能離開調用棧的。每個異步函數(shù)在被送入調用棧之前必須通過回調隊列。 翻譯:瘋狂的技術宅原文:https://www.valentinog.com/bl... 本文首發(fā)微信公眾號:前端先鋒歡迎關注,每天都給你推送新鮮的前端技術文章 sh...

    Simon_Zhou 評論0 收藏0
  • 前端人員必須知道的三個問題

    摘要:第一個問題前端都做哪些事呢,前端都需要哪些技術呢前端發(fā)展的三個階段初級階段入門常見標簽,新增的,語義化標簽等等選擇器,背景,文本,鏈接,列表,盒模型,定位,浮動,新增的屬性柵格化系統(tǒng),按鈕,表單,導航數(shù)據(jù)類型,對象,函數(shù),運算符,語句,,選 第一個問題:前端都做哪些事呢,前端都需要哪些技術呢 前端發(fā)展的三個階段: 初級階段:(入門) html:常見標簽,html5新增的,語義化標簽等等...

    zollero 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<