javascript - 当我们调用 web api 函数时,javascript 会创建执行上下文吗?

标签 javascript

我知道每当我调用我自己编写的函数时,Javascript 都会创建一个执行上下文。例如:

function sum(a, b) {
  return a + b;
}

// new execution context will be created here:
sum()

但是,当我调用 setTimeOut() 或 fetch() 等 Web api 函数时会发生什么

最佳答案

是的,所有函数调用都会导致创建执行上下文。

首先介绍一点背景知识,以便后续的解释更容易理解。规范讨论了内部槽,这些是必须实现的抽象属性和方法。它们不暴露在外面,所以你不能直接使用它们,它们用于实现。该规范使用双方括号中的名称,例如 [[Name]] - 指的是名为“name”的内部插槽。

考虑到这一点,我们也 clarify what is a function according to the spec (滚动到6.1.7.2部分的底部):

Table 7 summarizes additional essential internal methods that are supported by objects that may be called as functions. A function object is an object that supports the [[Call]] internal method. A constructor is an object that supports the [[Construct]] internal method. Every object that supports [[Construct]] must support [[Call]]; that is, every constructor must be a function object. Therefore, a constructor may also be referred to as a constructor function or constructor function object.

Table 7然后更抽象地描述了 [[Call]] 和 [[Construct]] 的作用。无论如何,简而言之,它是一个具有内部槽 [[Call]] 的对象

最后,我们可以看看[[Call]]。引用章节9.2 ECMAScript Function Objects的规范摘自 how [[Call]] should work 章节:

9.2.1 [[Call]] ( thisArgument, argumentsList )

The [[Call]] internal method for an ECMAScript function object F is called with parameters thisArgument and argumentsList, a List of ECMAScript language values. The following steps are taken:

  1. Assert: F is an ECMAScript function object.
  2. If F.[[IsClassConstructor]] is true, throw a TypeError exception.
  3. Let callerContext be the running execution context.
  4. Let calleeContext be PrepareForOrdinaryCall(F, undefined).
  5. Assert: calleeContext is now the running execution context.
  6. Perform OrdinaryCallBindThis(F, calleeContext, thisArgument).
  7. Let result be OrdinaryCallEvaluateBody(F, argumentsList).
  8. Remove calleeContext from the execution context stack and restore callerContext as the running execution context.
  9. If result.[[Type]] is return, return NormalCompletion(result.[[Value]]).
  10. ReturnIfAbrupt(result).
  11. Return NormalCompletion(undefined).

这是完整的部分,它适用于“正常”功能 - 由您或我创建的功能。全套步骤实际上是无关紧要的,我只是为了完整性才将其包括在内。重要的部分是第 4 步。 - 我不会引用 PrepareForOrdinaryCall 的全部内容。因为除了这些之外,还有更多的步骤与我们无关:

  1. Let calleeContext be a new ECMAScript code execution context.
  2. Push calleeContext onto the execution context stack; calleeContext is now the running execution context.
  3. Return calleeContext.

因此,简而言之,该函数获得一个新的运行执行上下文并将其放入堆栈中。好的。然后在[[Call]]的第8步,执行上下文被从堆栈中删除。

<小时/>

现在,让我们看一下 9.3 Built-in Function Objects 部分。这些是由环境提供并符合 ECMAScript 规范的函数对象,例如 ObjectArrayparseInt 等。允许这些内置函数在语言本身中实现(不一定是 JavaScript,请记住 ECMAScript 是标准,因此它将是实现标准的语言)或提供 到环境,这意味着可能用不同的语言实现。不过,规范说:

If a built-in function object is not implemented as an ECMAScript function it must provide [[Call]] and [[Construct]] internal methods that conform to the following definitions:

因此,即使提供了,函数仍然必须提供[[Call]]槽。和here is the behaviour it should follow :

9.3.1 [[Call]] ( thisArgument, argumentsList )

The [[Call]] internal method for a built-in function object F is called with parameters thisArgument and argumentsList, a List of ECMAScript language values. The following steps are taken:

  1. Let callerContext be the running execution context.
  2. If callerContext is not already suspended, suspend callerContext.
  3. Let calleeContext be a new execution context.
  4. Set the Function of calleeContext to F.
  5. Let calleeRealm be F.[[Realm]].
  6. Set the Realm of calleeContext to calleeRealm.
  7. Set the ScriptOrModule of calleeContext to F.[[ScriptOrModule]].
  8. Perform any necessary implementation-defined initialization of calleeContext.
  9. Push calleeContext onto the execution context stack; calleeContext is now the running execution context.
  10. Let result be the Completion Record that is the result of evaluating F in a manner that conforms to the specification of F.thisArgument is the this value, argumentsList provides the named parameters, and the NewTarget value is undefined.
  11. Remove calleeContext from the execution context stack and restore callerContext as the running execution context.
  12. Return result.

同样,全套步骤是无关紧要的。重要的是 3.、9. 和 11. - 创建新的执行上下文,将其推送到堆栈,最后将其删除。步骤 8. 允许对执行上下文进行任何特定于实现的更改。

<小时/>

这些部分规定了运行函数的工作方式。在这两种情况下,都会创建新的执行上下文,将其放入堆栈中,然后在函数完成后将其删除。

为了完整起见,这里是 chapter 8.3 . Execution Contexts如果你想了解更多关于他们的信息。总结一下重要部分,每个线程的任意一点最多有一个正在运行的执行上下文。 正在运行的执行堆栈也被定义为一个 LIFO 结构,当前正在运行的执行上下文位于顶部。

关于javascript - 当我们调用 web api 函数时,javascript 会创建执行上下文吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60892069/

相关文章:

php - 正确处理外来字符/表情符号

javascript - 如何使用 HTML5 在 Canvas 中绘制心电图监视器?

javascript - Node.js SQLite 3 返回 promise

javascript - 无法更改 onclick 上的文本

javascript - 如何使用Promise.promisify确保正确的 "this"?

javascript - onScroll 通过在屏幕上可见将类添加到 div

javascript - addClass() 基于另一个类的存在?

javascript - 页面加载时只加载一个 JavaScript 函数。

javascript - 在 Javascript 中迭代数组集合

javascript - 动态项目 View 模型 knockout