在现代Web开发中,浏览器异步加载优化是提升用户体验的关键环节。本文将通过实际代码对比,展示不同异步加载方案的差异。
传统异步加载问题
首先看一个典型的异步加载场景:
// 问题代码示例
function loadScript(src) {
const script = document.createElement('script');
script.src = src;
document.head.appendChild(script);
// 这里无法正确处理异步完成事件
return script;
}
// 使用方式
const script1 = loadScript('/js/lib1.js');
const script2 = loadScript('/js/lib2.js');
这种写法存在严重问题:无法知道脚本何时加载完成,可能导致依赖关系混乱。
Promise优化方案
使用Promise封装异步加载,可以更好地控制执行流程:
function loadScriptWithPromise(src) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = src;
script.onload = () => resolve(script);
script.onerror = () => reject(new Error(`Script load failed: ${src}`));
document.head.appendChild(script);
});
}
// 使用方式
loadScriptWithPromise('/js/lib1.js')
.then(() => loadScriptWithPromise('/js/lib2.js'))
.then(() => {
console.log('所有脚本加载完成');
// 执行后续逻辑
})
.catch(error => console.error(error));
Async/Await最佳实践
结合async/await语法,代码更加清晰易读:
async function loadScriptsSequentially(scripts) {
try {
for (const src of scripts) {
await loadScriptWithPromise(src);
console.log(`脚本 ${src} 加载完成`);
}
return '所有脚本加载成功';
} catch (error) {
console.error('脚本加载失败:', error);
throw error;
}
}
// 使用方式
(async () => {
try {
const result = await loadScriptsSequentially([
'/js/lib1.js',
'/js/lib2.js',
'/js/lib3.js'
]);
console.log(result);
} catch (error) {
console.error('加载失败:', error);
}
})();
并行加载优化
对于无依赖关系的脚本,可以并行加载以提升性能:
async function loadScriptsParallel(scripts) {
try {
const promises = scripts.map(src => loadScriptWithPromise(src));
await Promise.all(promises);
console.log('所有脚本并行加载完成');
return '加载成功';
} catch (error) {
console.error('部分脚本加载失败:', error);
throw error;
}
}
// 使用方式
loadScriptsParallel(['/js/lib1.js', '/js/lib2.js'])
.then(() => console.log('并行加载完成'))
.catch(error => console.error('并行加载失败:', error));
通过对比可以看出,从传统回调到Promise再到async/await的演进,让异步加载代码更加可靠和易维护。建议在实际项目中优先使用async/await方案,结合Promise.all实现并行加载优化。

讨论