在uniapp中使用uni.showModal的时候,当页面使用uni.reLaunch切换到其他页面面之后,原页面已经被关闭了,但是接口还在执行,执行成功之后弹出uni.showModal。
为了测试这个问题,我们先执行uni.reLaunch跳转,再定义一个计时器来弹出uni.showModal
uni.reLaunch({
url:'/pages/homePage/index'
})
setTimeout(() => {
uni.showModal({ title: "系统提示",content:"测试提示!" });
}, 10000)
跳转之后,uni.showModal依旧可以在新页面弹出,我们来分析一下切换其他页面为什么还能弹出uni.showModal
1.uni.showModal
uni.showModal是uni-app提供的API,用于在当前页面显示一个模态弹窗
官网说明:在非H5端,本章的所有弹出控件都是原生控件,层级最高,可覆盖video、map、tabbar等原生控件。(层级高)
2.uni.reLaunch(OBJECT)
uni.reLaunch(OBJECT)官网说明关闭所有页面,打开到应用内的某个页面
所以原页面已经被关闭,经测试确实已关闭
3.JavaScript执行环境
setTimeout 是 Web API 的一部分,它在浏览器的主线程中运行,即使切换到其他页面,只要当前页面实例没有被销毁,定时器仍然会继续执行
4.Vue页面生命周期
当使用 uni.navigateTo 或类似方法跳转到其他页面时,当前页面实际上并没有被销毁,页面实例仍然存在于内存中,所以定时器回调函数依然有效
5.Vue页面跳转与异步逻辑清理
1. 页面跳转与异步任务的关系
-
页面跳转 ≠ 代码执行环境销毁
- 页面跳转只是改变了视图层的显示
- JavaScript执行环境仍然存在,除非页面被销毁
-
异步任务独立于页面生命周期
-
setTimeout
、Promise
、fetch
等异步操作一旦启动就会继续执行 - 即使页面已经跳转或隐藏,这些任务仍在事件循环中等待执行
-
2. 不同跳转方式的行为差异
跳转方法 | 页面状态 | 异步任务 |
---|---|---|
uni.navigateTo |
页面隐藏,实例保留 | 异步任务继续执行 |
uni.redirectTo |
页面销毁 | 异步任务仍会执行 |
uni.reLaunch |
所有页面销毁 | 异步任务仍可能执行 |
uni.switchTab |
非tab页面被销毁 | 异步任务仍会执行 |
3.为什么页面销毁后异步任务仍执行
- JavaScript 事件循环机制:
- 当您调用 setTimeout 时,回调函数立即被添加到事件循环的任务队列中
- 即使后续页面被销毁,这个任务仍然在队列中等待执行
- JavaScript 是单线程的,任务一旦加入队列就会被执行
- 内存中的任务队列:
- 异步任务(包括定时器)存储在浏览器/运行环境的任务队列中
- 页面销毁只是移除了页面的 DOM 和 Vue 组件实例
- 但已经在事件循环中的任务并不依赖于页面实例的存在
6.JavaScript 的基本特性
- JavaScript 执行环境与异步任务
任务队列机制
JavaScript 使用事件循环(Event Loop)处理异步任务
setTimeout 等异步操作会将回调函数放入任务队列
任务队列独立于页面 DOM 结构和组件实例存在 - 页面销毁的实质
页面销毁 ≠ JavaScript 执行环境销毁
页面销毁只是移除了 DOM 元素和 Vue 组件实例
浏览器的 JavaScript 执行环境仍然运行
全局变量和已经启动的异步任务继续在事件循环中等待执行
这是 JavaScript 的核心特性之一:异步任务的生命周期独立于创建它们的组件或页面。开发者必须显式地管理这些异步任务,确保在不需要时进行清理,避免内存泄漏和意外行为。
总结:
无论使用 uni.redirectTo、uni.reLaunch 还是 uni.switchTab,页面销毁都不会影响已经加入事件循环的异步任务。这是 JavaScript 的基本特性而非bug,开发者必须手动管理这些异步任务的生命周期。
7.关于事件循环和Vue单页面的关系
1. 事件循环机制
- 执行流程如下:
- 调用 uni.reLaunch - 这是一个异步API调用,会被添加到任务队列中
- 调用 setTimeout - 这个定时器回调也会被添加到任务队列中
- 函数执行完毕 - 当前执行栈清空
- 事件循环处理任务 - 事件循环会按照顺序处理队列中的任务
- 关键点是:这两个操作都被添加到了事件循环的任务队列中,并且都会被执行。
2. Vue单页应用的影响
- 在uni-app这样的单页应用框架中:
- 页面切换 ≠不等于 页面卸载
- 页面切换只是改变了路由和组件的显示状态
- Vue组件实例可能仍然存在于内存中
- 组件的执行上下文并未被销毁
- JavaScript执行环境持续存在
8. Vue SPA 的基本特征
1.单页面实例
整个应用运行在单一的HTML页面中
页面切换实际上是组件的挂载和卸载
JavaScript运行环境始终保持活跃状态
// Vue组件生命周期与异步任务
created() {
// 组件创建时启动异步任务
this.timer = setTimeout(() => {
// 即使组件被销毁,这个回调仍会执行
}, 10000)
},
beforeDestroy() {
// 需要手动清理异步任务
clearTimeout(this.timer)
}
2. uni-app 中 Vue SPA 的特殊性
页面作为组件
// 每个页面实际上是一个Vue组件
defineOptions({
name: 'mine', // 页面组件名称
})
// 页面跳转 = 组件切换
uni.reLaunch({
url:'/pages/homePage/index' // 切换到另一个Vue组件
})
3. 与传统多页面应用的对比
特性 | Vue SPA | 传统多页面应用 |
---|---|---|
JavaScript环境 | 持续存在 | 页面跳转后重置 |
异步任务生命周期 | 独立于页面 | 随页面销毁而终止 |
内存管理 | 需手动清理 | 自动清理 |
总结:
Vue单页应用的架构使得JavaScript执行环境持续存在,页面切换只是组件的挂载/卸载操作。因此,异步任务的生命周期独立于页面组件的生命周期,需要开发者手动管理这些任务的清理工作。这是Vue SPA的重要特性,理解这一点对于避免内存泄漏和意外行为至关重要。
9.总结:
Vue单页应用的架构使得JavaScript执行环境持续存在,整个应用运行在同一个JavaScript上下文中
定时器等异步任务不受页面切换影响
即使页面开始跳转,已经加入事件循环的定时器任务仍然会执行,因为它与页面的显示状态无关。
异步任务一旦被添加到事件循环中,就会独立于页面状态继续执行,这是JavaScript的基本特性。