JavaScript 中的重入性

问题描述 投票:0回答:2

我想提高对可重入这个词的理解。

这个函数是可重入的吗?

function* foo() {
  yield 1;
  yield 2;
}

还有这个?

function foo() {
  return 1;
}

还有这个?

var x = 0;
function foo() {
  return x++;
}

还有这个?

function foo() {
  setTimeout(foo, 1000);
}
javascript reentrancy
2个回答
8
投票

可重入函数是可以恢复执行的函数:

在计算中,如果计算机程序或子例程可以在执行过程中被中断,然后在其先前的调用完成执行之前再次安全地调用(“重新进入”),则该计算机程序或子例程被称为可重入。

在浏览器/节点 JavaScript 中,所有多处理都是协作的(没有中断或上下文切换)。 JavaScript 中的常规函数始终运行完成。 (1)

因此,在您的情况下 - 唯一的可重入函数是第一个函数,因为它不会运行其代码直至完成,并且可以在稍后恢复。

  • 第二个函数只是一个常规函数。
  • 第三个使用外部作用域,这有点类似,因为它让函数保存某种状态。但这不是一回事,因为功能无法恢复。
  • 第四个立即运行完成(它安排了另一次调用 - 但这取决于 平台 而不是 JavaScript)。

确实 - 可以说生成器使用可重入语法在 JavaScript 中实现协作式多任务处理。在生成器之前,所有代码都运行完成。

(1) 或者说它永远不会停止,但它永远不会被打断。另外 - 在公共平台上。有些平台(如 Rhino)违反了规则。它们非常罕见,并且不使用与浏览器/节点 JS 相同的并发执行模型。


0
投票

JavaScript 没有可重入的概念,因为对于可重入,您需要第二个线程来调用正在暂停的同一函数。

即使使用示例(1)中的

yield
,该函数也会被暂停并在下一次迭代中恢复,但是您不能让另一个线程在暂停时再次调用同一函数,因为没有其他线程。如果您在单个线程中执行此操作(如下面的代码所示)并再次调用生成器函数,它会返回一个新的不同函数。这就是为什么它被称为生成器函数。所以你不要叫同一个。

function* foo(index) {
  while (index < 2) {
    yield index;
    index++;
  }
}

const iterator = foo(0);

console.log(iterator.next().value);
// Expected output: 0

const iterator2 = foo(0);
if (iterator === iterator2) console.log('same');
else console.log('not same function');

console.log(iterator.next().value);
// Expected output: 1

console.log(iterator2.next().value);
// Expected output: 0

输出:

> 0
> "not same function"
> 1
> 0

总而言之,要谈论可重入,您需要多线程。如果没有多线程,答案纯粹是理论上的。有人可能会说所有 JavaScript 函数都是可重入的,因为它们不容易受到重入问题的影响。另一位可能会说它们不是,因为它们不能被打断。

即使有

yield
,功能也会被中断吗?并非如此,它只是返回一个新生成的函数,该函数将运行完成以覆盖一次迭代。

这只是一个理论上的讨论,因为即使我们弄错了,也不会发生什么不好的事情,因为我们没有第二个线程来第二次同时调用它!

© www.soinside.com 2019 - 2024. All rights reserved.