语义解析器贪心Promise解析优先级调整及未完全解析提示实现问题
问题根因
你的问题和Promise执行优先级无关,属于架构设计的逻辑疏漏:
你所有可用于匹配的类型都来自传入parseElements的元素集合,当你遍历完所有元素、完成全部parseElement调用后,所有能被注册的类型就已经全部写入registredTypes。此时waitForTypes中剩余的监听对应的类型,就是当前批次永远无法命中的缺失类型,不会有后续逻辑触发它们的回调,对应的Promise会永远处于pending状态,不可能被resolve。
修复方案
我们只需要在所有元素遍历完成后,主动终止所有未命中的类型等待逻辑,再根据所有类型匹配的结果输出对应提示即可,修改点如下:
- 扩展事件类,新增缺失类型的终止逻辑,给等待中的Promise返回reject结果
- 解析完全部元素后,主动触发缺失类型的终止逻辑
- 使用
Promise.allSettled替代Promise.all处理类型匹配结果,兼容部分类型匹配失败的场景
修改后的可运行代码
class Element{ name = ""; typeID = ""; type = null; constructor(name, typeID){ this.name = name; this.typeID = typeID; } } class Events{ waitForTypes = {}; waitForType(typeName, cb){ if(!this.waitForTypes[typeName]){ this.waitForTypes[typeName] = []; } this.waitForTypes[typeName].push(cb); } triggerTypeFound(typeName){ if(this.waitForTypes[typeName] && this.waitForTypes[typeName].length > 0){ for(let cb of this.waitForTypes[typeName]){ cb(null, this.registredTypes[typeName]) } delete this.waitForTypes[typeName] } } // 新增:终止所有缺失类型的等待,返回错误 failAllMissingTypes(){ Object.keys(this.waitForTypes).forEach(typeName => { for(let cb of this.waitForTypes[typeName]){ cb(new Error(`类型${typeName}不存在`), null) } delete this.waitForTypes[typeName] }) } } class Parser extends Events{ registredTypes = {}; // 原代码此处写为数组不合理,修正为对象 typePromises = []; resolveType(element){ console.log("resolve type: "+ element.name) this.registredTypes[element.name] = element; this.triggerTypeFound(element.name) } getType(typeId){ if(this.registredTypes[typeId]){ return Promise.resolve(this.registredTypes[typeId]); } else { return new Promise((resolve, reject) => { this.waitForType(typeId, (err, type) => { if(err) return reject(err) resolve(type) }) }); } } parseElement(element){ console.log("parse Element " + element.name); this.resolveType(element); let typePromise = this.getType(element.typeID).then(type => { console.log("set Type for " + element.name); element.type = type return element }); this.typePromises.push(typePromise) } parseElements(elements){ for(let element of elements){ this.parseElement(element); } // 所有元素解析完成后,直接终止所有未命中的类型等待 this.failAllMissingTypes() console.log("parsing finished"); } }
测试逻辑
正常场景(所有类型可匹配)
let elements = [ new Element("A", "B"), new Element("B", "B"), new Element("C", "B"), ]; let parser = new Parser() parser.parseElements(elements) Promise.allSettled(parser.typePromises).then(results => { const allSuccess = results.every(r => r.status === 'fulfilled') if(allSuccess){ console.log("all types are resolved"); } else { console.log("parsing finished, not all types are resolved"); } })
运行后会输出all types are resolved。
缺失类型场景
let elements = [ new Element("A", "B") ]; let parser = new Parser() parser.parseElements(elements) Promise.allSettled(parser.typePromises).then(results => { const allSuccess = results.every(r => r.status === 'fulfilled') if(allSuccess){ console.log("all types are resolved"); } else { console.log("parsing finished, not all types are resolved"); } })
运行后会输出parsing finished, not all types are resolved。
内容的提问来源于stack exchange,提问作者fehrlich
相关产品推荐
相关产品推荐

