var resolve;
var head = { next: new Promise( r => resolve = r ) };
function addData(d) {
resolve({
data: d,
next: new Promise(r => resolve = r)
});
}

我编写了上面的代码来实现与linked-list类似的东西,而列表中的数据是异步加载的。
这个"链接列表"的负责人是head
。列表中的每个节点都有两个字段.data
和.next
,就像普通的链接列表一样。 .next
是一个承诺,它将解析为列表中的下一个节点。
每次调用addData(...)
时,列表中当前最后一个节点的.next
字段将解析为新节点,从而成为新的最后一个节点。
我已在Node.js中验证了上述代码的功能,并且它按预期工作。以下是我用来验证行为的代码:
var resolve;
var head = { next: new Promise( r => resolve = r ) };
function addData(d) { resolve({ data: d, next: new Promise(r => resolve = r) }); }
async function verify() {
while(true) {
head = await head.next;
console.log(head.data);
}
}
verify();
addData(1); // outputs: 1
addData(2); // outputs: 2
addData(3); // outputs: 3

但是,我不确定此结构是否存在任何潜在问题(内存,效率)。另外,我特别担心这一行:
resolve({data: d, next: new Promise(r => resolve = r})
同时调用和分配resolve。哪个应该首先发生,分配或功能名称解析?这是一种未定义的行为吗?
谢谢!
答案 0 :(得分:0)
首先应该发生哪种情况,分配或功能名称解析?
函数名称解析在评估参数之前发生(对象文字,包括Promise
构造函数调用,后者又调用回调,其中包括赋值)。
这是一种未定义的行为吗?
没有。但代码闻起来。
有更好/更优雅的方法吗?
是。它主要取决于数据结构的生成方式。如果您使用的是函数式方法,我建议使用递归函数:
function getStream(i) {
return new Promise(resolve => {
setTimeout(resolve, 100);
}).then(() => ({
data: i,
next: getStream(i+1)
}));
}
(async function() {
for (var data, next, head = getStream(1); {data, next} = await head; head = next) {
console.log(data);
}
}());
如果您使用其他人生成数据的命令式方法,我会将列表称为异步队列并放入适当的结构,但您的addData
代码很好(除了你可以使用额外变量管理的resolve
混淆之外。
答案 1 :(得分:0)
正如Bergi所指出的,这不是未定义的行为,但有一些方法可以实现这一点并不会让人感到困惑。
例如,您可以编写addData
函数,以便它不会分配resolve
函数并在同一语句中调用它:
function addData(d) {
let newResolve;
resolve({ data: d, next: new Promise(r => newResolve = r) });
resolve = newResolve;
}
看起来您可能正在使用非常迂回的方法来创建流或可观察集合,在这种情况下,您可能最好使用其中一个的现有实现。