Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

重学js——ES规范定义的任务和任务队列(Jobs and Job Queues) #51

Open
lizhongzhen11 opened this issue Oct 28, 2019 · 0 comments
Labels
js基础 Good for newcomers 重学js 重学js系列 规范+MDN

Comments

@lizhongzhen11
Copy link
Owner

lizhongzhen11 commented Oct 28, 2019

Jobs and Job Queues

Job 是抽象操作,当 当前没有其他ECMAScript计算正在进行时,它将启动ECMAScript计算。可以将 Job 抽象操作定义为接受任意一组任务参数。

只有当 没有运行时执行上下文 并且 执行上下文栈为空 时任务才会被启动执行。PendingJob 是对将来执行任务的请求。PendingJob 是一个内置的 Record,字段见下表:

字段名 意义
[[Job]] 任务抽象操作名 启动执行此 PendingJob 时执行的抽象操作。
[[Arguments]] List类型值 表示当 PendingJob 激活时,会被传递给[[Job]]的参数列。
[[Realm]] 领域记录 PendingJob 启动时的初始执行上下文的领域记录。
[[ScriptOrModule]] Script Record or Module Record PendingJob 启动时的初始执行上下文的脚本或模块。
[[HostDefined]] 可以是任何值,默认值是 undefined 保留给需要将其他信息与 PendingJob 关联的主机环境使用的字段。

一旦某个任务启动执行,该任务将会一直执行直到完成。在当前运行的任务完成前,其它任何任务都不会启动。 但是,当前正在运行的任务或外部事件可能会导致其他 PendingJob 排队,这些任务可能在当前正在运行的任务完成后的某个时间启动。

任务队列是PendingJob记录的先进先出队列。每个任务队列都有名字并且完整的可用任务队列集由ECMAScript实现定义。每个ECMAScript实现至少有下表中列出的 两种 任务队列:

名称 意义
ScriptJobs 验证和评估ECMAScript脚本和模块源文本的任务队列。见规范1015章节。
PromiseJobs 响应 Promise 解决的任务队列(见Promise Objects)

通过在任务队列上使包含任务抽象操作名称和任何必要参数值的 PendingJob 记录入队,来请求将来执行任务。当没有运行时执行上下文和执行上下文栈为空时,ECMAScript的实现从任务队列中移除第一个 PendingJob 并且使用 PendingJob 包含的信息创建执行上下文并同时始执行关联的Job抽象操作。

来自单个任务队列的 PendingJob 记录始终以先进先出顺序启动。规范没有定义服务多个任务队列的顺序。 ECMAScript实现可以将任务队列的 PendingJob 记录的先进先出求值与一个或多个其他任务队列的 PendingJob 记录的求值交织在一起。一个实现必须定义当没有运行时执行上下文并且所有任务队列为空时会发生什么。

通常,ECMAScript实现将使用至少一个 PendingJob 预先初始化其任务队列,并且其中一个任务将是第一个要执行的任务。

如果当前任务完成并且所有任务队列为空,则实现可以选择释放所有资源并终止。或者,它可以选择等待某些特定于实现的代理或机制来排队新的 PendingJob 请求。

EnqueueJob ( queueName, job, arguments )

创建和管理任务以及任务队列的步骤:

  1. Assert(断言)Type(queueName)是 String 类型并且其值是被实现认可的任务队列的名字。
  2. Assert(断言)job是任务的名字。
  3. Assert(断言)arguments是一个具有与任务所需参数数量相同的元素数量的列表。
  4. 让过程变量callerContext保存运行时执行上下文。
  5. 让过程变量callerRealm成为callerContext的领域。
  6. 让过程变量callerScriptOrModule成为callerContextScriptOrModule
  7. 定义过程变量pedding,初始值为PendingJob { [[Job]]: job, [[Arguments]]: arguments, [[Realm]]: callerRealm, [[ScriptOrModule]]: callerScriptOrModule, [[HostDefined]]: undefined }.
  8. 执行任何实现或主机环境定义的pedding处理。这可能包括修改[[HostDefined]]字段或pedding的任何其他字段。
  9. 在由queueName命名的任务队列的后面添加pedding
  10. 返回NormalCompletion(empty).

RunJobs ()

任务队列的执行步骤:

  1. 执行 InitializeHostDefinedRealm()
  2. 以依赖于实现的方式,获取零个或多个ECMAScript脚本和/或ECMAScript模块的ECMAScript源文本(请参见第10节Source Code)和任何相关的主机定义值。对于每个这样的sourceTexthostDefined
    • 如果sourceText是脚本源代码,那么
      • 执行EnqueueJob("ScriptJobs", ScriptEvaluationJob, « sourceText, hostDefined »).
    • 否则,
      • 断言:sourceText是模块源代码
      • 执行EnqueueJob("ScriptJobs", TopLevelModuleEvaluationJob, « sourceText, hostDefined »)
  3. 重复执行下面操作,
    • 挂起运行时执行上下文并且把它从执行上下文栈中移除。
    • 断言:执行上下文栈现在是空的。
    • 定义过程变量nextQueue,让它成为以实现定义的方式选择的非空任务队列。如果所有的任务队列为空,那么结果由实现定义。
    • 定义过程变量nextPending,令其为nextQueue前面的 PendingJob 记录。从nextQueue移除该记录。
    • 定义过程变量newContext作为新的执行上下文
    • 设置newContextFunction字段值为 null
    • 设置newContextRealm字段值为nextQueue.[[Realm]]
    • 设置newContextScriptOrModule字段值为nextPending.[[ScriptOrModule]]
    • newContext推入执行上下文栈中;这时newContext位于栈顶,成为当前的运行时执行上下文
    • 使用nextPending执行任何实现或主机环境定义的任务初始化。
    • 定义过程变量result,使其成为 执行由nextPending.[[Job]]定义并使用了nextPending.[[Arguments]]作为参数的 抽象操作的 结果。
    • 如果result是一个abrupt completion(非normal类型的completion),执行HostReportErrors(« result.[[Value]] »)

注意

经典面试题:

console.log('start')
setTimeout(() => console.log('setTimeout'), 0)
new Promise(res => {
  console.log('new Promise')
  res()
}).then(val => console.log('Promise then'))
console.log('end')

// 合理的打印结果为(有的浏览器实现有问题)
start
new Promise
end
Promise then
setTimeout

这条题涉及到 宏任务微任务 概念,可惜本文全篇都没有提到这两个术语,而且,整个规范都没有提到!!!
我就懵逼了,难不成不是规范,那么为何有那么多人统一叫这两个专业术语呢???
后来看知乎才知道,这两个术语出自 HTML Event Loops规范!!!

拓展阅读

  1. 宏任务和微任务
  2. Using microtasks in JavaScript with queueMicrotask()
  3. ECMAScript 的 Job Queues 和 Event loop 有什么关系?(看flyingsoul的回答)
  4. Event Loops
  5. MDN —— 并发模型与事件循环
@lizhongzhen11 lizhongzhen11 added the js基础 Good for newcomers label Oct 28, 2019
This was referenced Oct 28, 2019
@lizhongzhen11 lizhongzhen11 added the 重学js 重学js系列 规范+MDN label Jan 6, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
js基础 Good for newcomers 重学js 重学js系列 规范+MDN
Projects
None yet
Development

No branches or pull requests

1 participant