小程序网络监控大揭秘:如何实现实时监听网络变化

前几天写了一篇"5.25秒变0.023秒:小程序图片优化全攻略"
;介绍了一些小程序图片优化技巧,在文章中提到我们可以借助当前用户的网络状态去加载对应分辨率的图片。下面我们就实现一下这个功能。

需求分析

首先我们需要去写一个下载方法,通过下载来计算请求耗时,然后通过所需耗时来判断网络状态,如果网络状态不好,则进行几次重试,看看是否有更好的网络状态。同时我们还需要使用wx.onNetworkStatusChange这个api来监听网络状态的变化;该api会在用户网络切换时候触发,一旦触发,我们需要重新执行下载方法来判断当前的网络状态。

功能实现

我这里demo使用uni-app开发,所以有些api可能是uni.开头,如果你使用小程序原生开发,换成wx.即可。

新建/utils/networkManager.js,我们先定义一些基本的参数:

class NetworkManager {
    constructor() {
        // 最大重试次数
        this.MAX_RETRY_COUNT = 3
        // 当前重试次数
        this.retryCount = 0
        // 当前网络状态
        this.currentNetworkStatus = ''
        // 网络状态改变回调
        this.statusChangeCallback = null
        // 图片地址
        this.url = ''
    }
}

然后我们去添加两个函数,用来设置图片地址和网络状态改变的回调函数:

class NetworkManager {
    constructor() {
        // ...省略
    }
    /**
     * 设置网络状态变化的回调函数
     * @param {*} callback 
     */
    setChangeCallback(callback) {
        this.statusChangeCallback = callback
    }

    // 设置请求的url
    setRequestUrl(url) {
        this.url = url
    }
}

如何判断当前网络到底好不好呢?我们可以通过uni.downloadFile来下载一张1M-2M大小的图片,通过下载时间来判断网络情况。当请求耗时在1000ms以内,则认为网络极好,如果介于1000-1500ms之间,则认为网络好,如果大于1500ms,则认为网络差。如果网络非常差的时候,我们需要多请求几次,来持续判断网络是否有好转,如果超过我们定义的最大重试次数就停止请求。

class NetworkManager {
    constructor() {
        // ...省略
    }
    // 请求方法
    request() {
        return new Promise((resolve, reject) => {
            // 记录当前时间
            const startTime = Date.now()
            uni.downloadFile({
                url: `${this.url}?timer=${startTime}`,
                success: (res) => {
                    // 记录结束时间
                    const endTime = Date.now()
                    // 时间差
                    const duration = endTime - startTime
                    // 判断网络情况
                    this.checkNetworkStatus(duration)
                    resolve(res)
                },
                fail: (res) => {
                    // 进行重试
                    this.retryCount++
                    if (this.retryCount < this.MAX_RETRY_COUNT) {
                        this.request()
                    } else {
                        console.log('网络状态不佳,已停止')
                        // 重试次数归零
                        this.retryCount = 0
                        reject(res)
                    }
                },
            })
        })
    }

    /**
     * 判断网络状态
     * @param {*} duration 请求耗时ms
     */
    checkNetworkStatus(duration) {
        const previousStatus = this.currentNetworkStatus
        if (duration < 1000) {
            this.currentNetworkStatus = 'veryGood'
        } else if (duration >= 1000 && duration <= 1500) {
            this.currentNetworkStatus = 'good'
        } else {
            this.currentNetworkStatus = 'poor'
            // 请求失败,开始判断
            if (this.retryCount < this.MAX_RETRY_COUNT) {
                this.retryCount++
                this.request()
            } else {
                // 达到最大重试次数,停止递归
                this.retryCount = 0
                console.log('网络状态不佳,已停止')
            }
        }

        // 判断网络状态是否发生变化,如果有变化,就通知回调函数
        if (previousStatus !== this.currentNetworkStatus && this.statusChangeCallback) {
            this.statusChangeCallback(this.currentNetworkStatus)
        }
    }
}

最后我们还需要写一个开启函数,用来启动网络监听,同时使用uni.onNetworkStatusChange来监听用户网络环境变化,如果有变化则进行一次请求。

class NetworkManager {
    constructor() {
        // ...省略
    }
    /**
     * 开启监听
     * @returns 
     */
    start() {
        if (!this.url) {
            console.error('请设置请求的url')
            return
        }
        // 执行请求
        this.request()
        // 网络环境变换后,重新请求
        uni.onNetworkStatusChange(() => {
            this.request()
        })
    }
}

使用方式

我们来看一下最终的使用方式:

// 使用示例
const networkManager = new NetworkManager()
// 设置请求的url
networkManager.setRequestUrl('https://lonjin.oss-cn-beijing.aliyuncs.com/weixin-test/wallhaven-o5g125.jpeg')
// 设置网络状态变化的回调函数
networkManager.setChangeCallback((newStatus) => {
    // 这里可以把结果存到全局变量中,在其他页面方便使用
    console.log('网络状态变化:', newStatus)
})
// 启动
networkManager.start()

总结

我们通过uni.downloadFile来下载一张图片,通过下载时间来判断网络情况,然后通过uni.onNetworkStatusChange监听网络环境变化,当网络环境变化时,重新请求;从而去根据网络状态去请求不同大小的资源文件,减少白屏时间,提升用户体验。

往期推荐文章📚:

🏷️"5.25秒变0.023秒:小程序图片优化全攻略"

🏷️如何封装优雅、高效的uni-app请求:让开发更轻松

🏷️uni-app开发小程序:项目架构以及经验分享

🏷️小程序TabBar创意动画(文末附完整源代码)