Console

现行标准 — 最后更新于

参与:
GitHub whatwg/console (新问题, 开放的问题)
在Matrix上聊天
提交:
GitHub whatwg/console/commits
此提交的快照
测试:
web-platform-tests console/ (正在进行的工作)
翻译 (非规范性):
日本語
简体中文
한국어

摘要

本规范定义了用于console调试功能的API。

状态

本规范是一个早期的工作成果,欢迎反馈以便更精确和兼容的定义。这也是编辑们的第一个规范,所以请给予善意和建设性的意见。

请加入我们的问题跟踪器进行更多讨论。

1. 命名空间 console

[Exposed=*]
namespace console { // but see namespace object requirements below
  // Logging
  undefined assert(optional boolean condition = false, any... data);
  undefined clear();
  undefined debug(any... data);
  undefined error(any... data);
  undefined info(any... data);
  undefined log(any... data);
  undefined table(optional any tabularData, optional sequence<DOMString> properties);
  undefined trace(any... data);
  undefined warn(any... data);
  undefined dir(optional any item, optional object? options);
  undefined dirxml(any... data);

  // Counting
  undefined count(optional DOMString label = "default");
  undefined countReset(optional DOMString label = "default");

  // Grouping
  undefined group(any... data);
  undefined groupCollapsed(any... data);
  undefined groupEnd();

  // Timing
  undefined time(optional DOMString label = "default");
  undefined timeLog(optional DOMString label = "default", any... data);
  undefined timeEnd(optional DOMString label = "default");
};

出于历史原因,console 是小写的。

重要的是,console 对脚本始终是可见且可用的,即使开发者控制台尚未打开或不存在。

出于历史上的Web兼容性原因,命名空间对象的console 的[[Prototype]]必须是一个空对象,就像通过ObjectCreate(%ObjectPrototype%) 创建的一样,而不是%ObjectPrototype%。

1.1. 日志函数

1.1.1. assert(condition, ...data)

  1. 如果condition为真,返回。

  2. 令message为一个没有任何格式说明符的字符串,通常表示断言失败(例如“Assertion failed”)。

  3. 如果data是空的,则将 message添加到data中。

  4. 否则:

    1. 令first为data[0]。

    2. 如果 first 不是字符串,则将 message 添加到 data 的开头。

    3. 否则:

      1. 令concat为message、U+003A (:)、U+0020 SPACE 和first的串联。

      2. 将data[0]设置为concat。

  5. 执行Logger("assert", data)。

1.1.2. clear()

  1. 清空适当的组堆栈。

  2. 如果环境可能,清空console。(否则,不执行任何操作。)

1.1.3. debug(...data)

  1. 执行Logger("debug", data)。

1.1.4. error(...data)

  1. 执行Logger("error", data)。

1.1.5. info(...data)

  1. 执行Logger("info", data)。

1.1.6. log(...data)

  1. 执行Logger("log", data)。

1.1.7. table(tabularData, properties)

尝试构造一个具有tabularData属性列(或使用properties)和tabularData行的表格,并将其记录为“log”日志级别。如果无法解析为表格,则退回仅记录参数。

待办事项:这将需要一个好的算法。

1.1.8. trace(...data)

  1. 令 trace 为某种实现定义的、可能是交互式的调用栈表示形式,表示调用此函数的位置。

  2. 可选地,将formattedData设置为Formatter(data)的结果,并将formattedData作为trace的标签。

  3. 执行Printer("trace", « trace »)。

函数在堆栈跟踪中打印的标识符是实现定义的。它也不保证与在 new Error().stack 中看到的标识符相同。

1.1.9. warn(...data)

  1. 执行Logger("warn", data)。

1.1.10. dir(item, options)

  1. 令object为应用了通用JavaScript对象格式化的item。

  2. 执行Printer("dir", « object », options)。

1.1.11. dirxml(...data)

  1. 令finalList为一个新的列表,初始为空。

  2. 对data中的每个item:

    1. 如果可能,令converted为item的DOM树表示;否则,令converted为应用了最佳有用格式化的item。

    2. 将converted添加到finalList中。

  3. 执行Logger("dirxml", finalList)。

1.2. 计数函数

每个console命名空间对象都有一个关联的计数映射,它是从字符串到数字的映射,初始为空。

1.2.1. count(label)

  1. 令map为关联的计数映射。

  2. 如果map[label] 存在,则将 map[label]设置为map[label] + 1。

  3. 否则,将 map[label]设置为1。

  4. 令concat为label、U+003A (:)、U+0020 SPACE 和ToString(map[label])的串联。

  5. 执行Logger("count", « concat »)。

1.2.2. countReset(label)

  1. 令map为关联的计数映射。

  2. 如果map[label] 存在,将 map[label]设置为0。

  3. 否则:

    1. 令message为一个没有任何格式说明符的字符串,通常表示给定标签没有关联的计数。

    2. 执行Logger("countReset", « message »)。

1.3. 分组函数

一个组是一个实现定义的、可能是交互式的视图,用于显示通过调用Printer生成的输出,其缩进级别比其父级多一级。每个console 命名空间对象都有一个关联的组栈,它是一个栈,初始为空。只有组栈中的最后一个组会承载通过调用Printer生成的输出。

1.3.1. group(...data)

  1. 令group为一个新的组。

  2. 如果data不是空的,令groupLabel为Formatter(data)的结果。否则,令groupLabel为一个表示组的实现选择的标签。

  3. 将groupLabel作为group的标签。

  4. 可选地,如果环境支持交互式组,则group应默认展开。

  5. 执行Printer("group", « group »)。

  6. 将group推入适当的组堆栈。

1.3.2. groupCollapsed(...data)

  1. 令group为一个新的组。

  2. 如果data不是空的,令groupLabel为Formatter(data)的结果。否则,令groupLabel为一个表示组的实现选择的标签。

  3. 将groupLabel作为group的标签。

  4. 可选地,如果环境支持交互式组,则group应默认折叠。

  5. 执行Printer("groupCollapsed", « group »)。

  6. 将group推入适当的组堆栈。

1.3.3. groupEnd()

  1. 弹出最后一个组从组堆栈。

1.4. 计时函数

每个console命名空间对象都有一个关联的计时器表,它是从字符串到时间的映射,初始为空。

1.4.1. time(label)

  1. 如果关联的计时器表中包含一个键为label的条目,则返回,并可选地向console报告一个警告,指出标签为label的计时器已启动。

  2. 否则,将关联的计时器表中的键label的条目的值设置为当前时间。

1.4.2. timeLog(label, ...data)

  1. 让 timerTable 成为关联的 计时器表。

  2. 让 startTime 为 timerTable[label]。

  3. 令 duration 为一个字符串,表示当前时间与 startTime 之间的差异,格式为实现定义。

    "4650","4650.69 ms","5 seconds" 和 "00:05" 都是合理的方式来显示 4650.69 ms 的持续时间。

  4. 让 concat 为 label、U+003A (:)、U+0020 SPACE 和 duration 的连接。

  5. 前置 concat 到 data。

  6. 执行 Printer("timeLog", data)。

对timeLog()的调用中data参数包含在Logger的调用中,以便用户在计时器的生命周期内提供带有一些额外数据的中间计时日志。例如:
console.time("MyTimer");
console.timeLog("MyTimer", "Starting application up…");
// Perhaps some code runs to bootstrap a complex app
// ...
console.timeLog("MyTimer", "UI is setup, making API calls now");
// Perhaps some fetch()'s here filling the app with data
// ...
console.timeEnd("MyTimer");

1.4.3. timeEnd(label)

  1. 令timerTable为关联的计时器表。

  2. 令startTime为timerTable[label]。

  3. 移除 timerTable[label]。

  4. 令 duration 为一个字符串,表示当前时间与 startTime 之间的差异,格式为实现定义。

  5. 令concat为label、U+003A (:)、U+0020 SPACE 和duration的串联。

  6. 执行Printer("timeEnd", « concat »)。

参见whatwg/console#134,了解在给定的label不存在于关联的计时器表中时,使timeEnd()和timeLog()正式向console报告警告的计划。

2. 支持的抽象操作

2.1. Logger(logLevel, args)

logger操作接受一个日志级别和一个列表作为其他参数。其主要输出是将结果打印到控制台的实现定义的副作用。本规范描述了在此过程中如何处理格式说明符。

  1. 如果args是空的,则返回。

  2. 令first为args[0]。

  3. 令rest为args中first之后的所有元素。

  4. 如果rest是空的,则执行Printer(logLevel, « first ») 并返回。

  5. 否则,执行Printer(logLevel, Formatter(args))。

  6. 返回undefined。

在从算法返回之前进行打印是很重要的。许多开发者控制台会打印输入的最后一个操作的结果。在这些控制台中,当开发者输入console.log("hello!")时,它会首先打印“hello!”,然后打印从console.log调用返回的undefined值。

指示在返回之前完成打印

2.2. Formatter(args)

formatter操作尝试使用其他参数格式化提供的第一个参数。它将尝试格式化输入,直到第一个参数中没有剩余的格式说明符,或者没有剩余的参数。它返回一个适合打印的对象列表。

  1. 如果args的大小为1,则返回args。

  2. 令target为args的第一个元素。

  3. 令current为args的第二个元素。

  4. 从左到右在target中找到第一个可能的格式说明符specifier。

  5. 如果没有找到格式说明符,则返回args。

  6. 否则:

    1. 如果specifier是%s,令converted为调用(%String%, undefined, « current »)的结果。

    2. 如果specifier是%d或%i:

      1. 如果 current 是一个 Symbol,则令 converted 为 NaN

      2. 否则,令 converted 为调用(%parseInt%, undefined, « current, 10 ») 的结果。

    3. 如果specifier是%f:

      1. 如果 current 是一个 Symbol,则令 converted 为 NaN

      2. 否则,令converted为调用(%parseFloat%, undefined, « current »)的结果。

    4. 如果specifier是%o,可选地令converted为应用了最佳有用格式化的current。

    5. 如果specifier是%O,可选地令converted为应用了通用JavaScript对象格式化的current。

    6. 待办事项:处理%c

    7. 如果前面的步骤中的任何一个设置了converted,则将target中的specifier替换为converted。

  7. 令result为一个列表,其中包含target及args中从第三个开始的元素。

  8. 返回Formatter(result)。

2.2.1. 格式说明符摘要

以下是上述算法处理的格式说明符的说明性摘要。

说明符 用途 类型转换
%s 替代的元素将被转换为字符串 %String%(element)
%d 或 %i 替代的元素将被转换为整数 %parseInt%(element, 10)
%f 替代的元素将被转换为浮点数 %parseFloat%(element, 10)
%o 元素以最佳有用格式化显示 不适用
%O 元素以通用JavaScript对象格式化显示 不适用
%c 应用提供的CSS 不适用

2.3. Printer(logLevel, args[, options])

打印操作是实现定义的。它接受一个表示严重性的日志级别、一个要打印的参数列表,以及一个可选的实现特定格式选项对象。出现在 args 中的元素将是以下之一:

如果传递了 options 对象,并且它不是 undefined 或 null,实现可以使用 options 对 args 中的元素应用实现定义的格式化。

实现如何打印 args 由实现决定,但实现应通过空格或类似的方式分隔对象,因为这已成为开发者的预期。

在调用打印操作时,所有格式说明符都将被考虑在内,并且任何旨在被格式说明符使用的参数都不会出现在 args 中。实现的任务只是打印该列表。通过调用 Printer 生成的输出应仅出现在最后一个组中,该组位于适当的组栈中(如果组栈不为空),否则出现在控制台的其他地方。

如果在调用打印操作时控制台未打开,实现应缓冲消息以便将来显示,缓冲的消息数量应限制在实现定义的范围内(通常至少为 100 条)。

2.3.1. logLevel严重性的指示

每个console函数在调用Printer时使用一个唯一的logLevel参数值,允许实现根据消息的来源函数自定义每条打印消息。然而,通常的做法是将某些函数组合在一起,并以类似的方式处理它们的输出,分为四个大类。此表总结了这些常见的分组:

分组 console 函数 描述
log log(), trace(), dir(), dirxml(), group(), groupCollapsed(), debug(), timeLog() 通用日志
info count(), info(), timeEnd() 信息性日志
warn warn(), countReset() 提醒用户的日志
error error(), assert() 指示错误的日志

这些分组旨在记录常见做法,并不限制实现为每个函数提供特殊行为,如以下示例所示:

在这里,你可以看到一个实现选择使timeEnd()生成的输出为蓝色,而info()保持较为中性的颜色。

演示timeEnd和info格式化差异

调用count()可能不会总是打印新输出,而是可能更新先前输出的计数。

演示count行为

2.3.2. Printer 用户体验创新

由于 Printer 是实现定义的,因此在其实现中常见到用户体验(UX)方面的创新。以下是一些潜在 UX 增强的非详尽列表:

2.3.3. 常见对象格式

通常,对象会以适合其上下文的格式打印。本节描述了对象在其上下文中被格式化为最有用的常见方式。需要注意的是,本节中描述的格式化应用于实现定义的对象表示形式,这些表示形式最终会传递到Printer,格式化的实际副作用将在那里体现。

具有通用 JavaScript 对象格式化的对象是通用 JavaScript 对象的一个可能可扩展的表示形式。具有最优用格式化的对象是实现定义的、可能是交互式的对象表示形式,被认为是最有用和信息量最大的。

2.3.4. Node.js中的示例Printer

在Node.js平台上实现Printer操作的最简单方法是将先前格式化的参数用空格分隔后连接起来,并将输出写入stdout或stderr。

使用[ECMASCRIPT]的Node.js示例实现:

const util = require('util');

function print(logLevel, ...args) {
  const message = util.format(...args);

  if (logLevel === 'error') {
    process.stderr.write(message + '\n');
  } else if (logLevel === 'log' || logLevel === 'info' || logLevel === 'warn') {
    process.stdout.write(message + '\n');
  }
}

在这里,大部分工作由util.format函数完成。它将嵌套的对象字符串化,并将非字符串参数转换为可读的字符串版本,例如undefined变为字符串“undefined”,false变为“false”:

print('log', 'duck', [{foo: 'bar'}]);     // prints: duck [ { foo: 'bar' } ]\n on stdout
print('log', 'duck', false);              // prints: duck false\n on stdout
print('log', 'duck', undefined);          // prints: duck undefined\n on stdout

2.4. 向console报告警告

为了在给定一个警告的通用描述description的情况下向console报告警告,实现必须执行以下步骤:

  1. 令 warning 为从 description 派生的实现定义字符串。

  2. 执行Printer("reportWarning", « warning »)。

致谢

编辑们想感谢 Boris Zbarsky, Brent S.A. Cowgill, Brian Grinstead, Corey Farwell, Ian Kilpatrick, Jeff Carpenter, Joseph Pecoraro, Justin Woo, Luc Martin, Noah Bass, Paul Irish, Raphaël, 和 Victor Costan 对本规范的贡献。你们太棒了!

本标准由Terin Stock (terin@terinstock.com)、Robert Kowalski (rok@kowalski.gd)和Dominic Farolino (domfarolino@gmail.com) 编写,Domenic Denicola (Google, d@domenic.me) 提供了主要帮助。

知识产权

Copyright © WHATWG (Apple, Google, Mozilla, Microsoft)。本作品根据Creative Commons Attribution 4.0 International License 授权许可。在将部分内容并入源代码的范围内,该部分源代码根据BSD 3-Clause License授权许可。

这是现行标准。那些对专利审查版本感兴趣的人应查看现行标准审查草案。

索引

本规范定义的术语

引用定义的术语

参考文献

规范性引用

[ECMASCRIPT]
ECMAScript语言规范。URL: https://tc39.es/ecma262/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola。Infra 标准。现行标准。URL: https://infra.spec.whatwg.org/
[WEBIDL]
Edgar Chen; Timothy Gu。Web IDL标准。现行标准。URL: https://webidl.spec.whatwg.org/

IDL 索引

[Exposed=*]
namespace console { // but see namespace object requirements below
  // Logging
  undefined assert(optional boolean condition = false, any... data);
  undefined clear();
  undefined debug(any... data);
  undefined error(any... data);
  undefined info(any... data);
  undefined log(any... data);
  undefined table(optional any tabularData, optional sequence<DOMString> properties);
  undefined trace(any... data);
  undefined warn(any... data);
  undefined dir(optional any item, optional object? options);
  undefined dirxml(any... data);

  // Counting
  undefined count(optional DOMString label = "default");
  undefined countReset(optional DOMString label = "default");

  // Grouping
  undefined group(any... data);
  undefined groupCollapsed(any... data);
  undefined groupEnd();

  // Timing
  undefined time(optional DOMString label = "default");
  undefined timeLog(optional DOMString label = "default", any... data);
  undefined timeEnd(optional DOMString label = "default");
};

✔MDN
✔MDN
✔MDN
✔MDN
✔MDN
✔MDN
✔MDN
✔MDN
✔MDN
✔MDN
✔MDN
✔MDN
✔MDN
✔MDN
✔MDN
✔MDN
✔MDN
✔MDN
✔MDN
✔MDN