女王她妈 發表於 2020-3-10 13:40:00

Go进行wasm编程

<p>wasm即webAssemble,是一种不针对特定平台的二进制格式文件。Go从1.11开始支持wasm,最初通过js.NewCallBack()注册函数,1.12开始换成了FuncOf()。</p>
<p>Go开发wasm需要一个go文件用于编写实现代码,编译成.wasm文件;需要一个wasm_exec.js文件,这个是Go提供的,可以从 Go 安装目录的 misc 子目录里找到,将它直接拷贝过来。它实现了和 WebAssembly 模块交互的功能;另外就是需要一个HTML文件用于加载wasm文件。当然为了工作起来,我们还要实现一个简单的HTTP服务。</p>
<p><strong>一、用Go编写代码并编译成wasm文件</strong></p>
<div class="cnblogs_code"><img id="code_img_closed_ad41a56f-2ccd-48f1-8a37-12eefecbc8c1" class="code_img_closed" src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt=""><img id="code_img_opened_ad41a56f-2ccd-48f1-8a37-12eefecbc8c1" class="code_img_opened" style="display: none" src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" alt="">
<div id="cnblogs_code_open_ad41a56f-2ccd-48f1-8a37-12eefecbc8c1" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span> <span style="color: rgba(0, 0, 0, 1)">package main
</span><span style="color: rgba(0, 128, 128, 1)">2</span>
<span style="color: rgba(0, 128, 128, 1)">3</span> <span style="color: rgba(0, 0, 0, 1)">import (
</span><span style="color: rgba(0, 128, 128, 1)">4</span>   <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">fmt</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 128, 128, 1)">5</span>   <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">math/rand</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 128, 128, 1)">6</span>   <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">strconv</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 128, 128, 1)">7</span>   <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">syscall/js</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 128, 128, 1)">8</span>   <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">time</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 128, 128, 1)">9</span> <span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 10</span>
<span style="color: rgba(0, 128, 128, 1)"> 11</span> <span style="color: rgba(0, 0, 255, 1)">const</span><span style="color: rgba(0, 0, 0, 1)"> (
</span><span style="color: rgba(0, 128, 128, 1)"> 12</span>   width= <span style="color: rgba(128, 0, 128, 1)">400</span>
<span style="color: rgba(0, 128, 128, 1)"> 13</span>   height = <span style="color: rgba(128, 0, 128, 1)">400</span>
<span style="color: rgba(0, 128, 128, 1)"> 14</span> <span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 15</span>
<span style="color: rgba(0, 128, 128, 1)"> 16</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 生成 0 - 1 的随机数</span>
<span style="color: rgba(0, 128, 128, 1)"> 17</span> <span style="color: rgba(0, 0, 0, 1)">func getRandomNum() float32 {
</span><span style="color: rgba(0, 128, 128, 1)"> 18</span> <span style="color: rgba(0, 0, 0, 1)">    rand.New(rand.NewSource(time.Now().UnixNano()))
</span><span style="color: rgba(0, 128, 128, 1)"> 19</span>   n := float32(rand.Intn(<span style="color: rgba(128, 0, 128, 1)">10000</span><span style="color: rgba(0, 0, 0, 1)">))
</span><span style="color: rgba(0, 128, 128, 1)"> 20</span>   <span style="color: rgba(0, 0, 255, 1)">return</span> n / <span style="color: rgba(128, 0, 128, 1)">10000.0</span>
<span style="color: rgba(0, 128, 128, 1)"> 21</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)"> 22</span>
<span style="color: rgba(0, 128, 128, 1)"> 23</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 生成 0 - 10 的随机数</span>
<span style="color: rgba(0, 128, 128, 1)"> 24</span> <span style="color: rgba(0, 0, 0, 1)">func getRandomNum2() float32 {
</span><span style="color: rgba(0, 128, 128, 1)"> 25</span> <span style="color: rgba(0, 0, 0, 1)">    rand.New(rand.NewSource(time.Now().UnixNano()))
</span><span style="color: rgba(0, 128, 128, 1)"> 26</span>   n := float32(rand.Intn(<span style="color: rgba(128, 0, 128, 1)">10000</span><span style="color: rgba(0, 0, 0, 1)">))
</span><span style="color: rgba(0, 128, 128, 1)"> 27</span>   <span style="color: rgba(0, 0, 255, 1)">return</span> n / <span style="color: rgba(128, 0, 128, 1)">1000.0</span>
<span style="color: rgba(0, 128, 128, 1)"> 28</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)"> 29</span>
<span style="color: rgba(0, 128, 128, 1)"> 30</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 使用 canvas 绘制随机图</span>
<span style="color: rgba(0, 128, 128, 1)"> 31</span> <span style="color: rgba(0, 0, 0, 1)">func draw() {
</span><span style="color: rgba(0, 128, 128, 1)"> 32</span>   <span style="color: rgba(0, 0, 255, 1)">var</span> canvas js.Value =<span style="color: rgba(0, 0, 0, 1)"> js.
</span><span style="color: rgba(0, 128, 128, 1)"> 33</span> <span style="color: rgba(0, 0, 0, 1)">      Global().
</span><span style="color: rgba(0, 128, 128, 1)"> 34</span>         Get(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">document</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">).
</span><span style="color: rgba(0, 128, 128, 1)"> 35</span>         Call(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">getElementById</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">canvas</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 36</span>
<span style="color: rgba(0, 128, 128, 1)"> 37</span>   <span style="color: rgba(0, 0, 255, 1)">var</span> context js.Value = canvas.Call(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">getContext</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">2d</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 38</span>
<span style="color: rgba(0, 128, 128, 1)"> 39</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> reset</span>
<span style="color: rgba(0, 128, 128, 1)"> 40</span>   canvas.Set(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">height</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, height)
</span><span style="color: rgba(0, 128, 128, 1)"> 41</span>   canvas.Set(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">width</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, width)
</span><span style="color: rgba(0, 128, 128, 1)"> 42</span>   context.Call(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">clearRect</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 128, 1)">0</span>, <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">, width, height)
</span><span style="color: rgba(0, 128, 128, 1)"> 43</span>
<span style="color: rgba(0, 128, 128, 1)"> 44</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 随机绘制 50 条直线</span>
<span style="color: rgba(0, 128, 128, 1)"> 45</span>   <span style="color: rgba(0, 0, 255, 1)">var</span> clineStyle = `rgba(%d, %d, %d, <span style="color: rgba(128, 0, 128, 1)">0.5</span><span style="color: rgba(0, 0, 0, 1)">)`
</span><span style="color: rgba(0, 128, 128, 1)"> 46</span>   <span style="color: rgba(0, 0, 255, 1)">for</span> i := <span style="color: rgba(128, 0, 128, 1)">0</span>; i &lt; <span style="color: rgba(128, 0, 128, 1)">50</span>; i++<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)"> 47</span>         lineStyle := fmt.Sprintf(clineStyle, <span style="color: rgba(128, 0, 128, 1)">155</span>+<span style="color: rgba(0, 0, 255, 1)">int</span>(getRandomNum2()*<span style="color: rgba(128, 0, 128, 1)">10</span>), <span style="color: rgba(128, 0, 128, 1)">155</span>+<span style="color: rgba(0, 0, 255, 1)">int</span>(getRandomNum()*<span style="color: rgba(128, 0, 128, 1)">100</span>), <span style="color: rgba(128, 0, 128, 1)">155</span>+<span style="color: rgba(0, 0, 255, 1)">int</span>(getRandomNum()*<span style="color: rgba(128, 0, 128, 1)">100</span><span style="color: rgba(0, 0, 0, 1)">))
</span><span style="color: rgba(0, 128, 128, 1)"> 48</span> <span style="color: rgba(0, 0, 0, 1)">      fmt.Println(lineStyle)
</span><span style="color: rgba(0, 128, 128, 1)"> 49</span>         context.Call(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">beginPath</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 50</span>         context.Set(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">strokeStyle</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, lineStyle)
</span><span style="color: rgba(0, 128, 128, 1)"> 51</span>         context.Call(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">moveTo</span><span style="color: rgba(128, 0, 0, 1)">"</span>, getRandomNum()*width, getRandomNum()*<span style="color: rgba(0, 0, 0, 1)">height)
</span><span style="color: rgba(0, 128, 128, 1)"> 52</span>         context.Call(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">lineTo</span><span style="color: rgba(128, 0, 0, 1)">"</span>, getRandomNum()*width, getRandomNum()*<span style="color: rgba(0, 0, 0, 1)">height)
</span><span style="color: rgba(0, 128, 128, 1)"> 53</span>         context.Call(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">stroke</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 54</span> <span style="color: rgba(0, 0, 0, 1)">    }
</span><span style="color: rgba(0, 128, 128, 1)"> 55</span>
<span style="color: rgba(0, 128, 128, 1)"> 56</span>   context.Set(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">font</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">30px Arial</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 57</span>   context.Set(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">strokeStyle</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">blue</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 58</span>   <span style="color: rgba(0, 0, 255, 1)">for</span> i := <span style="color: rgba(128, 0, 128, 1)">0</span>; i &lt; <span style="color: rgba(128, 0, 128, 1)">10</span>; i++<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)"> 59</span>         context.Call(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">strokeText</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">hello wasm</span><span style="color: rgba(128, 0, 0, 1)">"</span>, (getRandomNum2()+<span style="color: rgba(128, 0, 128, 1)">1</span>)*<span style="color: rgba(128, 0, 128, 1)">10</span>+getRandomNum2()*<span style="color: rgba(128, 0, 128, 1)">10</span>, (getRandomNum2()+<span style="color: rgba(128, 0, 128, 1)">1</span>)*<span style="color: rgba(128, 0, 128, 1)">10</span>+getRandomNum2()*<span style="color: rgba(128, 0, 128, 1)">50</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 60</span> <span style="color: rgba(0, 0, 0, 1)">    }
</span><span style="color: rgba(0, 128, 128, 1)"> 61</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)"> 62</span>
<span style="color: rgba(0, 128, 128, 1)"> 63</span> <span style="color: rgba(0, 0, 0, 1)">func registerCallbackFunc() {
</span><span style="color: rgba(0, 128, 128, 1)"> 64</span>   cb := js.FuncOf(func(<span style="color: rgba(0, 0, 255, 1)">this</span> js.Value, args []js.Value) <span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)">{} {
</span><span style="color: rgba(0, 128, 128, 1)"> 65</span>         fmt.Println(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">button clicked</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 66</span>
<span style="color: rgba(0, 128, 128, 1)"> 67</span>         num1 := getElementByID(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">num1</span><span style="color: rgba(128, 0, 0, 1)">"</span>).Get(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">value</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">).String()
</span><span style="color: rgba(0, 128, 128, 1)"> 68</span>         v1, err :=<span style="color: rgba(0, 0, 0, 1)"> strconv.Atoi(num1)
</span><span style="color: rgba(0, 128, 128, 1)"> 69</span>         <span style="color: rgba(0, 0, 255, 1)">if</span> nil !=<span style="color: rgba(0, 0, 0, 1)"> err {
</span><span style="color: rgba(0, 128, 128, 1)"> 70</span>             fmt.Println(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">button clicked:</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, num1, err.Error())
</span><span style="color: rgba(0, 128, 128, 1)"> 71</span> <span style="color: rgba(0, 0, 0, 1)">            jsAlert().Invoke(err.Error())
</span><span style="color: rgba(0, 128, 128, 1)"> 72</span>             <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> panic(err)</span>
<span style="color: rgba(0, 128, 128, 1)"> 73</span>             <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> nil
</span><span style="color: rgba(0, 128, 128, 1)"> 74</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)"> 75</span>
<span style="color: rgba(0, 128, 128, 1)"> 76</span>         num2 := getElementByID(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">num2</span><span style="color: rgba(128, 0, 0, 1)">"</span>).Get(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">value</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">).String()
</span><span style="color: rgba(0, 128, 128, 1)"> 77</span>         v2, err :=<span style="color: rgba(0, 0, 0, 1)"> strconv.Atoi(num2)
</span><span style="color: rgba(0, 128, 128, 1)"> 78</span>         <span style="color: rgba(0, 0, 255, 1)">if</span> nil !=<span style="color: rgba(0, 0, 0, 1)"> err {
</span><span style="color: rgba(0, 128, 128, 1)"> 79</span>             fmt.Println(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">button clicked:</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, num2, err.Error())
</span><span style="color: rgba(0, 128, 128, 1)"> 80</span>             <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> panic(err)</span>
<span style="color: rgba(0, 128, 128, 1)"> 81</span>             <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> nil
</span><span style="color: rgba(0, 128, 128, 1)"> 82</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)"> 83</span>
<span style="color: rgba(0, 128, 128, 1)"> 84</span>         rlt := v1 +<span style="color: rgba(0, 0, 0, 1)"> v2
</span><span style="color: rgba(0, 128, 128, 1)"> 85</span>         getElementByID(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">rlt</span><span style="color: rgba(128, 0, 0, 1)">"</span>).Set(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">value</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, rlt)
</span><span style="color: rgba(0, 128, 128, 1)"> 86</span>
<span style="color: rgba(0, 128, 128, 1)"> 87</span>         <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> nil
</span><span style="color: rgba(0, 128, 128, 1)"> 88</span> <span style="color: rgba(0, 0, 0, 1)">    })
</span><span style="color: rgba(0, 128, 128, 1)"> 89</span>
<span style="color: rgba(0, 128, 128, 1)"> 90</span>   getElementByID(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">compute</span><span style="color: rgba(128, 0, 0, 1)">"</span>).Call(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">addEventListener</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">click</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, cb)
</span><span style="color: rgba(0, 128, 128, 1)"> 91</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)"> 92</span>
<span style="color: rgba(0, 128, 128, 1)"> 93</span> func getElementByID(id <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">) js.Value {
</span><span style="color: rgba(0, 128, 128, 1)"> 94</span>   <span style="color: rgba(0, 0, 255, 1)">return</span> js.Global().Get(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">document</span><span style="color: rgba(128, 0, 0, 1)">"</span>).Call(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">getElementById</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, id)
</span><span style="color: rgba(0, 128, 128, 1)"> 95</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)"> 96</span>
<span style="color: rgba(0, 128, 128, 1)"> 97</span> <span style="color: rgba(0, 0, 0, 1)">func jsAlert() js.Value {
</span><span style="color: rgba(0, 128, 128, 1)"> 98</span>   <span style="color: rgba(0, 0, 255, 1)">return</span> js.Global().Get(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">alert</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 99</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">100</span>
<span style="color: rgba(0, 128, 128, 1)">101</span> <span style="color: rgba(0, 0, 0, 1)">func main() {
</span><span style="color: rgba(0, 128, 128, 1)">102</span>   fmt.Println(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Hello, Go WebAssembly!</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">103</span> <span style="color: rgba(0, 0, 0, 1)">    draw()
</span><span style="color: rgba(0, 128, 128, 1)">104</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 通过js.Global().Get()拿到全局alert函数的引用</span>
<span style="color: rgba(0, 128, 128, 1)">105</span>   alert := js.Global().Get(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">alert</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">106</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 调用alert.Invoke来调用alert函数</span>
<span style="color: rgba(0, 128, 128, 1)">107</span>   alert.Invoke(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">hello world</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">108</span>
<span style="color: rgba(0, 128, 128, 1)">109</span> <span style="color: rgba(0, 0, 0, 1)">    registerCallbackFunc()
</span><span style="color: rgba(0, 128, 128, 1)">110</span> }</pre>
</div>
<span class="cnblogs_code_collapse">Go wasm代码</span></div>
<p>将代码编译成Wasm文件,需要设置编译环境。我用的VsCode,用powershell设置环境变量始终不能生效,于是换成了Bash:</p>
<p>执行:go env 查看环境,注意GOOS和GOARCH,如果是win 系统的话,默认应该是windows和amd64,为了编译出wasm文件,需要修改如下:</p>
<p>export GOOS=js</p>
<p>export GOARCH=wasm</p>
<p>否则编译的时候会提示奇怪的信息(不是提示环境问题),如果还是不对,可以设置CGO:</p>
<p>export CGO_ENABLED=0</p>
<p>当然我设置的1是没问题的。</p>
<p>最后编译生成wasm文件:</p>
<p>go build -o lib.wasm main.go</p>
<p>-o 是编译参数,指定输出的文件。</p>
<p>在Go里面要引入:syscall/js</p>
<p>通过js.Global().Get()获取js对象,既可以获取函数、也可以获取DOM元素。类型是js.Value。</p>
<p>如:</p>
<div>js.Global().Get("alert")</div>
<div>
<div>js.Global().Get("document")</div>
</div>
<p>如果是设置元素的属性调用Set(),如果是呼叫(执行)方法,调用Call("函数名","参数")。</p>
<p>如:</p>
<div>js.Global().Get("document").Call("getElementById",&nbsp;id)</div>
<div>&nbsp;</div>
<div>前面的代码演示了调用alert()、Input的读写、Canvas对象的操作。</div>
<p><strong>二、编写HTML</strong></p>
<div class="cnblogs_code"><img id="code_img_closed_27019644-73a8-45d1-a5bb-fadbc46e9d55" class="code_img_closed" src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt=""><img id="code_img_opened_27019644-73a8-45d1-a5bb-fadbc46e9d55" class="code_img_opened" style="display: none" src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" alt="">
<div id="cnblogs_code_open_27019644-73a8-45d1-a5bb-fadbc46e9d55" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">html</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 2</span>   <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">head</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 3</span>         <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">meta </span><span style="color: rgba(255, 0, 0, 1)">charset</span><span style="color: rgba(0, 0, 255, 1)">="utf-8"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 4</span>         <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">src</span><span style="color: rgba(0, 0, 255, 1)">="wasm_exec.js"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 5</span>         <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">            const go </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">new</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> Go();
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">            WebAssembly.instantiateStreaming(fetch(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">lib.wasm</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">), go.importObject).then((result) </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=&gt;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">                go.run(result.instance);
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">            });
</span><span style="color: rgba(0, 128, 128, 1)">10</span>         <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">11</span>   <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">head</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">12</span>   <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">body</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">13</span>         <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">canvas </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">='canvas'</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">canvas</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">br</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">14</span>         <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">input </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="num1"</span><span style="color: rgba(255, 0, 0, 1)"> type</span><span style="color: rgba(0, 0, 255, 1)">="number"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">15</span> <span style="color: rgba(0, 0, 0, 1)">      +
</span><span style="color: rgba(0, 128, 128, 1)">16</span>         <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">input </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="num2"</span><span style="color: rgba(255, 0, 0, 1)"> type</span><span style="color: rgba(0, 0, 255, 1)">="number"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">17</span> <span style="color: rgba(0, 0, 0, 1)">      =
</span><span style="color: rgba(0, 128, 128, 1)">18</span>         <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">input </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="rlt"</span><span style="color: rgba(255, 0, 0, 1)"> type</span><span style="color: rgba(0, 0, 255, 1)">="number"</span><span style="color: rgba(255, 0, 0, 1)"> readonly</span><span style="color: rgba(0, 0, 255, 1)">="readonly"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">19</span>         <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">button </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="compute"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>compute<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">button</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">20</span>   <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">body</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">21</span> <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">html</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span></pre>
</div>
<span class="cnblogs_code_collapse">index.html</span></div>
<p>HTML文件主要是定义界面元素,引入wasm_exec.js文件,调用刚才build的lib.wasm。</p>
<p><strong>三、编写一个HTTP服务</strong></p>
<p>Go 内置的 HTTP 服务器支持Content-Type 为 application/wasm。</p>
<div class="cnblogs_code"><img id="code_img_closed_72da3187-fea5-4a38-891e-db4dfb9ee42b" class="code_img_closed" src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt=""><img id="code_img_opened_72da3187-fea5-4a38-891e-db4dfb9ee42b" class="code_img_opened" style="display: none" src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" alt="">
<div id="cnblogs_code_open_72da3187-fea5-4a38-891e-db4dfb9ee42b" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 0, 1)">package main
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span>
<span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(0, 0, 0, 1)">import (
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span>   <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">flag</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 128, 128, 1)"> 5</span>   <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">log</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 128, 128, 1)"> 6</span>   <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">net/http</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span>
<span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 255, 1)">var</span><span style="color: rgba(0, 0, 0, 1)"> (
</span><span style="color: rgba(0, 128, 128, 1)">10</span>   listen = flag.String(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">listen</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">:8087</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">listen address</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">11</span>   dir    = flag.String(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">dir</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">.</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">files directory to serve</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">12</span> <span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">13</span>
<span style="color: rgba(0, 128, 128, 1)">14</span> <span style="color: rgba(0, 0, 0, 1)">func main() {
</span><span style="color: rgba(0, 128, 128, 1)">15</span> <span style="color: rgba(0, 0, 0, 1)">    flag.Parse()
</span><span style="color: rgba(0, 128, 128, 1)">16</span>   log.Printf(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">listening on %q...</span><span style="color: rgba(128, 0, 0, 1)">"</span>, *<span style="color: rgba(0, 0, 0, 1)">listen)
</span><span style="color: rgba(0, 128, 128, 1)">17</span>   err := http.ListenAndServe(*listen, http.FileServer(http.Dir(*<span style="color: rgba(0, 0, 0, 1)">dir)))
</span><span style="color: rgba(0, 128, 128, 1)">18</span> <span style="color: rgba(0, 0, 0, 1)">    log.Fatalln(err)
</span><span style="color: rgba(0, 128, 128, 1)">19</span> }</pre>
</div>
<span class="cnblogs_code_collapse">HTTP服务代码</span></div>
<p>这里要注意:之前为了编译wasm文件,修改了GOOS和GOARCH,现在为了运行http服务,我们必须恢复。</p>
<p>为了方便调试,我们可以在vscode里面新建一个终端,执行:</p>
<p>export GOOS=windows</p>
<p>export GOARCH=amd64</p>
<p>然后执行:</p>
<p>go run server.go</p>
<p>如果有防火墙提示网络访问,选择允许,然后会看到终端提示:</p>
<p>2020/03/10 09:27:12 listening on ":8087"...</p>
<p>这表示我们的HTTP服务启动好了。</p>
<p><strong>四、测试效果</strong></p>
<p>在浏览器里面输入:http://127.0.0.1:8087/</p>
<p>可以看到页面弹出了对话框:</p>
<p><img src="https://img2020.cnblogs.com/i-beta/50506/202003/50506-20200310093021559-1911678204.png" alt=""></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>然后出现了我们绘制的内容:</p>
<p><img src="https://img2020.cnblogs.com/i-beta/50506/202003/50506-20200310093119196-998898311.png" alt=""></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>在浏览器调试器里面看到输出内容:</p>
<p><img src="https://img2020.cnblogs.com/i-beta/50506/202003/50506-20200310093156932-490537705.png" alt=""></p>
<p>&nbsp;</p>
<p>&nbsp;页面上还有一个计算的功能,我们输入数字,点击按钮,发现没有反应,看调试器可以看见错误:</p>
<p><img src="https://img2020.cnblogs.com/i-beta/50506/202003/50506-20200310093243129-1018379288.png" alt=""></p>
<p>&nbsp;</p>
<p>信息提示很明确,回头看我们的Go代码,main()函数在执行了registerCallbackFunc()就结束退出了,</p>
<p>这个时候再去调用肯定是失败的,所以我们要让程序不能退出:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 0, 1)">func main() {
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span>   fmt.Println(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Hello, Go WebAssembly!</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(0, 0, 0, 1)">    draw()
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 通过js.Global().Get()拿到全局alert函数的引用</span>
<span style="color: rgba(0, 128, 128, 1)"> 5</span>   alert := js.Global().Get(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">alert</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 调用alert.Invoke来调用alert函数</span>
<span style="color: rgba(0, 128, 128, 1)"> 7</span>   alert.Invoke(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">hello world</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span>   done := make(chan <span style="color: rgba(0, 0, 255, 1)">struct</span>{}, <span style="color: rgba(128, 0, 128, 1)">0</span>) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 创建无缓冲通道</span>
<span style="color: rgba(0, 128, 128, 1)"> 9</span>
<span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 0, 1)">    registerCallbackFunc()
</span><span style="color: rgba(0, 128, 128, 1)">11</span>   &lt;-done    <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 阻塞</span>
<span style="color: rgba(0, 128, 128, 1)">12</span> }</pre>
</div>
<p>在第8行创建一个通道,然后在11行从通道读取内容,因为通道没有内容,所以会阻塞。</p>
<p>然后重新编译wasm文件,刷新网页,可以看到预期达到了:</p>
<p><img src="https://img2020.cnblogs.com/i-beta/50506/202003/50506-20200310093658122-954449449.png" alt=""></p>
<p>&nbsp;</p>
<p>&nbsp;这就是用Go开发Wasm的基本套路了。</p><br><br>
来源:https://www.cnblogs.com/codingnote/p/12453872.html
頁: [1]
查看完整版本: Go进行wasm编程