將GO編繹成JavaScript,用GO語言來寫前端程式碼

edithfang發表於2014-10-19
GopherJS是一個將GO編繹成JavaScript的開源專案, 下面的描述來自開源專案主頁,Github

GopherJS將GO程式碼編繹成純的JavaScript程式碼。它的主要目的是讓你有機會使用GO語言來寫前端程式碼。你可以線上玩一玩。

你可以使用GO優雅的型別系統和編繹時檢查系統,因此你有機會發現大量的潛在BUG,並可以更好的進行重構。想像一下你之前要處理多少有關JavaScript遺留的引數問題,因為你不確定會不會還有人在用這些老API。GopherJS會豪無怨言地幫你解決這些問題。你可以放心,這種BUG將不會再出現。

Goroutines

注*Goroutines是Go語言中一種輕量級的併發實現機制;可以理解為輕量級的多執行緒機制,不同的是Goroutines執行時還可以訪問當前上下文。

JavaScript沒有併發的概念(除了webworkers,但是與Goroutines不同,他們被隔離地太徹底了)。所以,JavaScript中的程式碼永遠不會被阻塞。一個阻塞的呼叫將會讓你的網頁停止響應。所以我們使用了一個帶參回撥來代替。

GopherJS對於這種限制做了大量的工作: 當一個指令被阻塞(比如通訊中的一個通道channel沒有好),整個棧就不會被執行(等待所有的函式都被呼叫過以後),其它goroutine會暫時休息。然後另外一個準備執行的goroutine會恢復執行(與本地變數一起恢復)。這種機制通過一個閉包來實現。

這種機制生成的程式碼效能非常好,但是還是沒有非阻塞系統(基於原生JS回撥)的好。這是GopherJS努力去克服的一面。

但是它也有一個優點,外部JavaScript從來不會被阻塞執行,但你可以使用go語法在JS中達到阻塞的效果。

這是一個Go編繹到JavaScript的示例,來自其Playgroud

GO的程式碼
package main
import (
  "fmt"
  "github.com/gopherjs/gopherjs/js"
)
func main() {
  fmt.Println("Hello, playground")
  js.Global.Call("alert", "Hello, JavaScript")
  println("Hello, JS console")
}


JavaScript程式碼
$packages["main"] = (function() {
  var $pkg = {}, fmt = $packages["fmt"], js = $packages["github.com/gopherjs/gopherjs/js"], main;
  main = function() {
    fmt.Println(new ($sliceType($emptyInterface))([new $String("Hello, playground")]));
    $global.alert($externalize("Hello, JavaScript", $String));
    console.log("Hello, JS console");
  };
  $pkg.$run = function($b) {
    $packages["github.com/gopherjs/gopherjs/js"].$init();
    $packages["runtime"].$init();
    $packages["errors"].$init();
    $packages["sync/atomic"].$init();
    $packages["sync"].$init();
    $packages["io"].$init();
    $packages["math"].$init();
    $packages["unicode"].$init();
    $packages["unicode/utf8"].$init();
    $packages["bytes"].$init();
    $packages["syscall"].$init();
    $packages["strings"].$init();
    $packages["time"].$init();
    $packages["os"].$init();
    $packages["strconv"].$init();
    $packages["reflect"].$init();
    $packages["fmt"].$init();
    $pkg.$init();
    main();
  };
  $pkg.$init = function() {
  };
  return $pkg;
})();


引入了非常多的預定義packages和物件如($global,$String)等,個人認為這樣的前端程式碼實用性並不強,冗餘非常明顯,降低了可維護。

目前GO的編繹系統檢查地非常嚴格,不允許一些未定義的外部全域性變數的直接訪問,如你得這樣訪問document:

JS程式碼:
document.write("Hello world!");


GO程式碼:
js.Global.Get("document").Call("write", "Hello world!")


這種機制造成了與外部第三方外掛(如jQuery)等配合起來非常不便。要寫很多額外程式碼。實用性比目前的CoffeeScript和TypeScript還要差很多。

評論(1)

相關文章