Golang中如何实现仅执行一次的JavaScript代码

Golang中如何实现仅执行一次的JavaScript代码 传统方法可能是在每个页面上放置一段代码来检查 JavaScript 是否已加载:

window.onload = function () {
    if (localStorage.getItem("hasCodeRunBefore") === null) {
        //load code...
        localStorage.setItem("hasCodeRunBefore", true);
    }
}

是否有可能调用一个“隐藏”页面,无论怎样都只运行一次?类似于伪代码:

func init() {
	tpl = template.Must(template.ParseGlob("public/tmpl/*.html"))
    load code into site for every windows (store in localStorage)?
}

更多关于Golang中如何实现仅执行一次的JavaScript代码的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

GonzaSaya: 使用 sync 包,你可以让某些代码只运行一次。

谢谢!但我该如何运行 JavaScript 并将其存储在 localStorage 中呢?

更多关于Golang中如何实现仅执行一次的JavaScript代码的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用 sync 包可以确保某些代码只执行一次:

网站图标

sync package - sync - Go Packages

sync 包提供了基本的同步原语,例如互斥锁。

示例:

package main

import (
	"fmt"
	"sync"
)

func main() {
	var once sync.Once
	onceBody := func() {
		fmt.Println("Only once")
	}
	done := make(chan bool)
	for i := 0; i < 10; i++ {
		go func() {
			once.Do(onceBody)
			done <- true
		}()
	}
	for i := 0; i < 10; i++ {
		<-done
	}
}

在Go中实现JavaScript代码仅执行一次,通常需要结合前端技术。以下是几种实现方式:

1. 使用模板注入一次性脚本

在Go模板中注入一个只在首次加载时执行的脚本:

// main.go
package main

import (
    "html/template"
    "net/http"
)

var tpl *template.Template
var scriptInjected bool

func init() {
    tpl = template.Must(template.ParseGlob("templates/*.html"))
}

func handler(w http.ResponseWriter, r *http.Request) {
    data := struct {
        InjectScript bool
    }{
        InjectScript: !scriptInjected,
    }
    
    if !scriptInjected {
        scriptInjected = true
    }
    
    tpl.ExecuteTemplate(w, "index.html", data)
}

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)
}
<!-- templates/index.html -->
<!DOCTYPE html>
<html>
<head>
    <title>一次性脚本示例</title>
</head>
<body>
    {{if .InjectScript}}
    <script>
        (function() {
            if (!window.__hasInitialized) {
                console.log("这段代码只执行一次");
                // 你的初始化代码
                window.__hasInitialized = true;
                
                // 或者使用localStorage
                if (!localStorage.getItem('appInitialized')) {
                    // 执行一次性操作
                    localStorage.setItem('appInitialized', 'true');
                }
            }
        })();
    </script>
    {{end}}
    
    <h1>页面内容</h1>
</body>
</html>

2. 使用Cookie控制脚本执行

// 设置一次性Cookie
func setOneTimeCookie(w http.ResponseWriter) bool {
    cookie, err := r.Cookie("script_executed")
    if err != nil {
        // 设置Cookie,标记脚本已执行
        http.SetCookie(w, &http.Cookie{
            Name:     "script_executed",
            Value:    "true",
            Path:     "/",
            MaxAge:   31536000, // 一年
            HttpOnly: false,
        })
        return true // 需要执行脚本
    }
    return false // 不需要执行脚本
}

// 在handler中使用
func handler(w http.ResponseWriter, r *http.Request) {
    shouldExecute := setOneTimeCookie(w)
    
    data := struct {
        ExecuteScript bool
    }{
        ExecuteScript: shouldExecute,
    }
    
    tpl.ExecuteTemplate(w, "index.html", data)
}

3. 使用服务端Session控制

package main

import (
    "github.com/gorilla/sessions"
    "html/template"
    "net/http"
)

var store = sessions.NewCookieStore([]byte("your-secret-key"))
var tpl *template.Template

func init() {
    tpl = template.Must(template.ParseGlob("templates/*.html"))
}

func handler(w http.ResponseWriter, r *http.Request) {
    session, _ := store.Get(r, "session-name")
    
    var shouldExecute bool
    if _, ok := session.Values["script_executed"]; !ok {
        session.Values["script_executed"] = true
        session.Save(r, w)
        shouldExecute = true
    }
    
    data := struct {
        ExecuteScript bool
    }{
        ExecuteScript: shouldExecute,
    }
    
    tpl.ExecuteTemplate(w, "index.html", data)
}

4. 纯前端解决方案(推荐)

如果不想依赖服务端状态,可以使用纯前端方案:

// 在模板中注入这个脚本
<script>
// 使用闭包确保只执行一次
var oneTimeExecution = (function() {
    var executed = false;
    return function() {
        if (!executed) {
            executed = true;
            
            // 你的初始化代码
            console.log("这段代码只执行一次");
            
            // 或者使用更持久的方式
            if (!window.oneTimeFlag) {
                // 执行一次性操作
                window.oneTimeFlag = true;
                
                // 使用localStorage跨会话保持状态
                if (!localStorage.getItem('appInitialized')) {
                    // 执行初始化
                    localStorage.setItem('appInitialized', 'true');
                    
                    // 执行你的业务逻辑
                    initializeApp();
                }
            }
        }
    };
})();

// 在页面加载时调用
window.addEventListener('load', oneTimeExecution);

function initializeApp() {
    // 你的初始化逻辑
    console.log("应用初始化完成");
}
</script>

5. 结合Go和JavaScript的完整示例

// main.go
package main

import (
    "html/template"
    "net/http"
    "time"
)

var tpl *template.Template

func init() {
    funcMap := template.FuncMap{
        "now": time.Now,
    }
    tpl = template.Must(template.New("").Funcs(funcMap).ParseGlob("templates/*.html"))
}

func handler(w http.ResponseWriter, r *http.Request) {
    // 生成唯一的版本号或时间戳
    version := time.Now().Unix()
    
    data := struct {
        Version int64
    }{
        Version: version,
    }
    
    tpl.ExecuteTemplate(w, "page.html", data)
}
<!-- templates/page.html -->
<!DOCTYPE html>
<html>
<head>
    <title>一次性脚本</title>
    <script>
        // 使用版本控制
        var currentVersion = {{.Version}};
        
        if (localStorage.getItem('appVersion') !== currentVersion.toString()) {
            // 版本变化,执行初始化
            console.log("执行版本: " + currentVersion);
            
            // 你的初始化代码
            initializeApp();
            
            // 更新存储的版本
            localStorage.setItem('appVersion', currentVersion.toString());
        }
        
        function initializeApp() {
            // 一次性初始化逻辑
            console.log("应用初始化");
        }
    </script>
</head>
<body>
    <h1>页面内容</h1>
</body>
</html>

这些方法可以根据你的具体需求选择使用。纯前端方案(使用localStorage)是最简单且不依赖服务端状态的方法,而结合Go的模板注入可以提供更精确的控制。

回到顶部