场景
基于vue开发的单页面系统,index.html页面加载的时候会按顺序加载多个js脚本文件。第一个加载执行的js文件是不含异步调用的配置文件,后续执行的其他脚本根据该配置文件里面的信息来执行。目前想把配置文件里面的部分配置存到数据库,然后通过接口调用的方式获取配置并可以界面化修改配置(从而避免直接打开前端js文件来维护配置)。
因为存数据库的配置涉及到整个系统的运行,必须要先获取到配置信息后才能执行后续js脚本逻辑。因此必须要将接口获取配置这一异步请求操作实现同步请求的效果。
解决方案
- 回调函数
通过将后续所有要执行的脚本全部放到请求回调函数里面来实现。现实情况是:系统初始化加载会加载好多个独立的js文件,而且除第一个配置脚本外,后续的其他脚本文件都是经过编译出来的文件,无法实现回调函数的方式。
- async/await
在平常的开发中,我们会使用async/await
语法糖来实现同步执行的效果,避免产生回调地狱。实现函数同步调用的前提是执行函数得处在 async
包裹的函数内部,适用于在同一个js文件且同一个函数体里面。但是我们目前的情况是:系统会加载多个js文件,无法把所有的脚本封装进一个统一的函数里面来调用。可以通过以下的一个简单示例来理解:
async function testAsync() {
const aa = await Promise.resolve('aa')
console.log(aa)
console.log('bb')
}
console.log('cc')
testAsync() // 执行结果:cc aa bb
- ajax设置为同步请求
通过配置ajax请求为同步请求来阻塞当前代码的执行,直到接收到服务器端的回应后才继续执行后续代码。该方式由于会阻塞代码执行,因此可能会导致页面空白,影响用户体验。
getConfig()
console.log('继续执行')
function getConfig() {
let xhr = null
// 兼容写法
if (window.XMLHttpRequest) {
// 标准浏览器
xhr = new XMLHttpRequest()
} else {
// IE6浏览器
// eslint-disable-next-line no-undef
xhr = new ActiveXObject('Microsoft.XMLHTTP')
}
// 将 xhr.open 的第三个参数改成 false,即由异步改成同步请求
xhr.open('GET', 'http://127.0.0.1:9990/index', false)
// 4、指定回调函数,处理得到的数据
xhr.onreadystatechange = function() {
// 通过判断 xhr 的 readyState,确定此次请求是否完成
if (this.readyState === 4) {
console.log('请求成功')
}
}
// 3、send() 方法发送一次请求
xhr.send(null)
// Ajax 后面的代码
console.log('After Ajax')
}
// 最终执行结果: 请求成功 After Ajax 继续执行