2017-02-09 28 views
0

以下JavaScript代码是否有未定义的行为?

var resolve; 
 

 
var head = { next: new Promise(r => resolve = r) }; 
 

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

我写上面的代码来实现类似链表的东西,而在列表中的数据异步加载。

这个“链表”的头是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})

哪里决心被调用,并在同一时间分配。首先应该发生什么,赋值或函数名称解析?这是一个未定义的行为?

谢谢!

+1

无论它是否有效,它肯定是钝的(难以阅读和理解代码的重点)。 – jfriend00

+0

@ jfriend00他只会保留整个链条,如果他保留了一个头部的参考,他不这样做。当然,很容易出错...... – Bergi

+0

@Bergi - 我已经删除了该评论,因为我已经得出结论,这太难理解正在发生什么(在我看来,由于这个原因,糟糕的代码)。但是,OP确实表示“像一个链表”,但我想它根本不是一个真正的链表。我想这只是前一个承诺的更高范围的缓存。没有太多更好的方法来做到这一点,它不那么钝,也不使用更高范围的“解析”变量? – jfriend00

回答

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你可以用一个额外的变量管理混淆)。

+0

谢谢你的回答!如果我必须实施这种“链接列表”结构,有没有更好的方法可以做到这一点? –

0

正如Bergi所指出的那样,这并不是未定义的行为,但有些方法可以实现这一点,但这并不令人感到困惑。

例如,你可以写addData功能,因此,它不分配resolve功能,并调用它在相同的语句:

function addData(d) { 
    let newResolve; 

    resolve({ data: d, next: new Promise(r => newResolve = r) }); 

    resolve = newResolve; 
} 

看起来你可能会使用一个非常迂回的方法来创建一个流或可观察的集合,在这种情况下,您最好使用其中一个的现有实现。

+0

如何存储延迟比存储'resolve'函数更好? – Bergi

+0

@Bergi对我来说似乎更清楚一点,但公平点。我已经改变了我的答案,以避免在同一语句中调用并分配'resolve'的混淆行。 – JLRishe

+0

谢谢你的回答和建议!用几句话来解释这个应用程序真的很复杂。我会尝试找到一些符合要求的现有实现.... –

相关问题