如何控制JavaScript Promise执行顺序,实现子对象优先初始化?
问题:控制嵌套对象反序列化的初始化顺序
场景与现有代码
我们需要反序列化包含type键的JSON对象:
type值为字符串,对应加载同名JS文件(如type="a"则加载a.js,文件内包含初始化函数a_init)- 对象可能包含
subobjects键,其值为对象数组,嵌套对象需按相同规则处理
现有实现代码如下:
var files = []; function load(obj) { if (!!obj["type"]) { let type = obj.type; let subobjects = obj.subobjects; let promise = new Promise(function(resolve) { let script = document.createElement("script"); script.setAttribute("src", type + ".js"); script.addEventListener("load",resolve); document.head.appendChild(script); }); promise.then(function() { if (!files.includes(type)) { files.push(type); if (subobjects instanceof Array) { for (element of subobjects) { load(element); } } let func = window[type + "_init"]; if (typeof(func) =="function") { func(obj); } } }); } }
测试用例与当前问题
测试对象:
{ "type": "a", "data": "foo", "subobjects": [ { "type": "b", "data": "1" } ] }
当前输出(a_init和b_init仅输出测试消息):
This is A This is B
我们需要子对象先完成初始化,即输出顺序为:
This is B This is A
当前代码中嵌套调用load仅生成新Promise,但不会等待子对象的异步操作完成就执行当前对象的init,导致顺序不符合预期。
解决方案:基于Promise的顺序控制
修改load函数,让它返回Promise,确保先完成所有子对象的初始化,再执行当前对象的init:
var files = []; function load(obj) { // 没有type的直接返回已完成的Promise if (!obj["type"]) return Promise.resolve(); let type = obj.type; let subobjects = obj.subobjects; // 1. 加载当前类型的脚本 const loadScriptPromise = new Promise(resolve => { const script = document.createElement("script"); script.src = `${type}.js`; script.addEventListener("load", resolve); document.head.appendChild(script); }); // 2. 等待脚本加载完成后,处理子对象并执行当前init return loadScriptPromise.then(() => { // 避免重复加载同类型脚本 if (files.includes(type)) return; files.push(type); // 处理子对象:等待所有子对象的load操作全部完成 const subPromises = (subobjects instanceof Array) ? subobjects.map(element => load(element)) : []; // 3. 所有子对象初始化完成后,再执行当前对象的init return Promise.all(subPromises).then(() => { const func = window[`${type}_init`]; if (typeof func === "function") { func(obj); } }); }); }
关键修改点
- 让
load返回Promise:这样可以通过Promise.all等待所有子对象的异步操作完成 - 调整执行顺序:脚本加载完成后,先触发所有子对象的
load并等待它们全部完成,最后再执行当前对象的init - 避免重复加载:保持原有的
files数组逻辑,防止同一类型脚本重复加载
调用时如果需要等待整个初始化流程完成,可以使用:
load(testObj).then(() => { console.log("所有对象初始化完成"); });
内容的提问来源于stack exchange,提问作者user1636349
相关产品推荐
相关产品推荐

