js pure front-end implementation redeployment to notify users to refresh the web page

Demand: Sometimes after going online, the user still stays on the old page. The user does not know that the web page has been redeployed. When jumping to the page, sometimes the js connection hash changes, causing an error and the user cannot jump to the new page, and the user cannot experience the new features. It needs to be optimized. Whenever customers enter the system after packaging and release, they will be prompted to update the system and prompt customers.

Solution: Upload a json file to the public, and then change the json every time it is packaged. The first time I got the ison data and saved it, and then polled the request until the time in the json data changed, and I prompted the user.

The front-end determines based on the hash value of the script src generated after packaging. Each package will generate a unique hash value. As long as it is polled to determine if it is different, it must have been redeployed.
Insert image description here

Insert image description here
Code implementation: Customize a js or ts file
RedeployMessage.ts
and copy and paste the following code into it

interface Options {
timer?: number
}

export class Updater {
    oldScript: string[] //存储第一次值也就是script 的hash 信息
    newScript: string[] //获取新的值 也就是新的script 的hash信息
    dispatch: Record<string, Function[]> //小型发布订阅通知用户更新了
    constructor(options: Options) {
        this.oldScript = [];
        this.newScript = []
        this.dispatch = {}
        this.init() //初始化
        this.timing(options?.timer)//轮询
    }


    async init() {
        const html: string = await this.getHtml()
        this.oldScript = this.parserScript(html)
    }

    async getHtml() {
        const html = await fetch('/').then(res => res.text());//读取index html
        return html
    }

    parserScript(html: string) {
        const reg = new RegExp(/<script(?:\s+[^>]*)?>(.*?)<\/script\s*>/ig) //script正则
        return html.match(reg) as string[] //匹配script标签
    }

    //发布订阅通知
    on(key: 'no-update' | 'update', fn: Function) {
        (this.dispatch[key] || (this.dispatch[key] = [])).push(fn)  
        return this;
    }

    compare(oldArr: string[], newArr: string[]) {
        const base = oldArr.length
        const arr = Array.from(new Set(oldArr.concat(newArr)))
        //如果新旧length 一样无更新
        if (arr.length === base) {
            this.dispatch['no-update'].forEach(fn => {
                fn()
            })
        
        } else {
            //否则通知更新
            this.dispatch['update'].forEach(fn => {
                fn()
            })
        }
    }

    timing(time = 10000) {
         //轮询
        setInterval(async () => {
            const newHtml = await this.getHtml()
            this.newScript = this.parserScript(newHtml)
            this.compare(this.oldScript, this.newScript)
        }, time)
    }
}

Then what? —Reference this ts file in the outermost App file.

If it is a vue project, put it in the onMoutend hook function

//实例化该类
const up = new Updater({
    timer:2000
})
//未更新通知
up.on('no-update',()=>{
   console.log('未更新')
})
//更新通知
up.on('update',()=>{
    console.log('更新了')
}) 

Insert image description here


If it is a react project, it can be placed in componentDidMount()

//实例化该类
const up = new Updater({
    timer:2000
})
//未更新通知
up.on('no-update',()=>{
   console.log('未更新')
})
//更新通知
up.on('update',()=>{
    console.log('更新了'),更新进行提示弹框消息。自己封装就好了,一般都有组件直接用
}) 

Insert image description here
Insert image description here

Pay attention to the possible problem, that is, it is prompted to update but the customer never clicks to update, and then the page will send a pop-up message after a timer. At this time, we must remember to clear the timer clearInterval().
That is, assign a variable when polling

 timing(time = 10000) {
     //轮询
  let clearTime =   setInterval(async () => {
        const newHtml = await this.getHtml()
        this.newScript = this.parserScript(newHtml)
        this.compare(this.oldScript, this.newScript)
    }, time)
}

然后再调用定时器的地方,清除,即 
//否则通知更新
        this.dispatch['update'].forEach(fn => {
            fn()
            clearInterval(this.clearTime)
        })

There is another solution that you can read what this blogger wrote and enter . I did not try. welcome to flirt

Guess you like

Origin blog.csdn.net/lzfengquan/article/details/131451542