deno學習(2)---從Hello World開始

deno的執行非常簡單,使用deno xx.ts即可。 從deno hello.ts出發,探究一下deno的運行機制。

  • 學習目標
    1. deno代碼的模塊
    2. 各模塊之間的交互模式

回顧

  • 在上一節學習過程中,已經知道了執行make指令之后,會將go代碼、ts代碼、js代碼已經node_module代碼打包。可以大致猜測一下,在整個deno項目里面,go會占一部分,js也會占一部分。作為js和go的交互模塊,v8worker也是很重要的一部分。

v8worker

  • v8worker本身是ry大神基于V8做的一個go和js調用的中間層。主體只有兩個功能:
    1. 接收消息
    • golang接收來自js的消息
//worker.go
func New(cb ReceiveMessageCallback) *Worker {
    //...
}
  • js接收來自golang的消息
V8Worker2.recv((ab: ArrayBuffer) => {
//...
}
  1. 發送消息給js
  • golang分送消息到js
//worker.go
func (w *Worker) SendBytes(msg []byte) error {
  • js分送消息到golang
V8Worker2.send(msg)

在deno里面,作者對v8worker做了簡單的封裝,在go和js層面分別做了一個 分發器。dispatch.godispatch.ts,分別提供了訂閱、發布功能。

dispatch.go

func Sub(channel string, cb Subscriber) {
    subscribers, ok := channels[channel]
    subscribers = append(subscribers, cb)
    channels[channel] = subscribers
}

func Pub(channel string, payload []byte) {
    wg.Add(1)
    resChan <- &BaseMsg{
        Channel: channel,
        Payload: payload,
    }
}

dispatch.js

export function sub(channel: string, cb: MessageCallback): void {
  let subscribers = channels.get(channel);
  subscribers.push(cb);
}

export function pub(channel: string, payload: Uint8Array): null | ArrayBuffer {
  const msg = pb.BaseMsg.fromObject({ channel, payload });
// ...
  return send(ab);
}

通過以上代碼,就可以實現一個訂閱者模式,從而實現數據交互。值得一提的是,數據交互格式為protobuf。這種方式相當安全、高效。

main.go

  • 通過下面代碼可以知道,deno的主入口就是 ./cmd/main.go文件
deno: msg.pb.go $(GO_FILES)
   go build -o deno ./cmd
  • ./cmd/main.go
package main

import (
    "github.com/ry/deno"
)
func main() {
    //初始化deno配置,預加載js代碼。形成bridger
    deno.Init()

    //執行denoMain()方法
    deno.Eval("deno_main.js", "denoMain()")
    deno.Loop()
}
  1. 初始化 2. 執行js 里面的 denoMain方法 3.執行一個輪詢
  • main.go./cmd/main.go引用了 deno包。Init、Eval、Loop都位于main.go

  • Init

    //創建所需文件夾 在 ${home}/.deno   創建 src cache 兩個文件夾
    createDirs()
    //訂閱 os
    InitOS()
    //訂閱echox
    InitEcho()
    //訂閱timers
    InitTimers()
    //訂閱fetch
    InitFetch()


    //一個v8工作線程
    worker = v8worker2.New(recv)

    //加載main.js代碼.
    //main.js就是Makefile里面通過
    /**
    #生成 dist/main.js 通過 ts文件 和 node_moduels
dist/main.js: $(TS_FILES) node_modules
    ./node_modules/.bin/tsc --noEmit # Only for type checking.
    ./node_modules/.bin/parcel build --out-dir=dist/ --log-level=1 --no-minify main.ts
        打包生成的代碼。
    */
    main_js = stringAsset("main.js")
    //加載main.js
    err := worker.Load("/main.js", main_js)
    exitOnError(err)
    //代碼的map,用于定位代碼.
    main_map = stringAsset("main.map")
  • Eval
    // It's up to library users to call
// deno.Eval("deno_main.js", "denoMain()")
func Eval(filename string, code string) {
    //執行代碼
    err := worker.Load(filename, code)
    exitOnError(err)
}
  • Loop

func Loop() {
    cwd, err := os.Getwd()
    check(err)
    /**
        可以將v8worker2 理解為一個C/S的架構。
        Client發送消息,Server端回復消息。
    */
    PubMsg("start", &Msg{
        Command:        Msg_START,
        StartCwd:       cwd,
        StartArgv:      workerArgs,
        StartDebugFlag: *flagDebug,
        StartMainJs:    main_js,
        StartMainMap:   main_map,
    })
    DispatchLoop()
}

執行流程

  1. 初始化。
    • 下面四個方法,通過V8注冊方法,實現對js調用的訂閱。
    InitOS()
    //訂閱echox
    InitEcho()
    //訂閱timers
    InitTimers()
    //訂閱fetch
    InitFetch()

os.go

//訂閱了os。提供了5種模式。
Sub("os", func(buf []byte) []byte {
        switch msg.Command {
        case Msg_CODE_FETCH:
        case Msg_CODE_CACHE:
        case Msg_EXIT:  
        case Msg_READ_FILE_SYNC:
                //讀取文件      
        case Msg_WRITE_FILE_SYNC:   
        }
    })

剩下三個大同小異,不做具體說明。

  - 加載 js文件
//會加載 /dist/main.js 文件
main_js = stringAsset("main.js")
//加載main.js,編譯并執行。
err := worker.Load("/main.js", main_js)
  1. 執行denoMain方法。
  • denoMain方法是 位于main.js 里面。實際上在打包之前,是位于main.ts下。
(window as any)["denoMain"] = () => {
  initTimers(); //初始化timer
  initFetch(); //初始化fetch 

//訂閱start事件。
  dispatch.sub("start", (payload: Uint8Array) => {
    runtime.setup(mainJs, mainMap);
//就是文件路徑
    const inputFn = argv[0];
//模塊加載
    const mod = runtime.resolveModule(inputFn, `${cwd}/`);
//執行編譯和運行ts代碼
    mod.compileAndRun();
  });

這里訂閱了start事件,等待觸發。觸發的時候,就是對ts文件做編譯、執行的時候。

  1. 開始Loop
    main.go
func Loop() {
    cwd, err := os.Getwd()
    /**
      觸發start事件。
    */
    PubMsg("start", &Msg{
        Command:        Msg_START,
        StartCwd:       cwd,
        StartArgv:      workerArgs,
        StartDebugFlag: *flagDebug,
        StartMainJs:    main_js,
        StartMainMap:   main_map,
    })
        //對消息輪詢,實現數據交換。
    DispatchLoop()
}

dispatch.go

func DispatchLoop() {
      // 對協程做監控。
    //實際上,Pub會新建一個協程消息,這里做監聽。有新信息就通過worker發送給js層。
    for {
        select {
        case msg := <-resChan:
            out, err := proto.Marshal(msg)
            err = worker.SendBytes(out)
        case <-doneChan:
            return
        }
}
image.png

總結

  • 目前來看deno是一個很簡單的執行ts的程序。效率也不是很高。實際上對ts的解析和執行都是在runtime時期運行的,相對于以前對typescript先編譯成js再使用的方式,是一種全新的嘗試。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,656評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,621評論 2 380

推薦閱讀更多精彩內容

  • 1.ios高性能編程 (1).內層 最小的內層平均值和峰值(2).耗電量 高效的算法和數據結構(3).初始化時...
    歐辰_OSR閱讀 29,511評論 8 265
  • Swift1> Swift和OC的區別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,131評論 1 32
  • 1. 分布式系統核心問題 參考書籍:《區塊鏈原理、設計與應用》 一致性問題例子:兩個不同的電影院買同一種電影票,如...
    molscar閱讀 927評論 0 0
  • 如果你要問妹迷們:為什么喜歡好妹妹?答案有很多,總結起來有幾個關鍵因素: 1.接地氣的小清新民謠配上“無節操”的逗...
    了了君閱讀 7,137評論 13 60
  • 你是風雨 我卻把你當彩虹 你是夜空 我卻把你當霓虹 數不清的星子 睡不醒的夢 你說我傻 把星子當珍寶 把夢境當人生
    一泡日照閱讀 195評論 4 3