mirror of
https://github.com/denoland/deno.git
synced 2024-11-28 16:20:57 -05:00
feat: add performance user timing APIs (#6421)
This commit is contained in:
parent
d01eb6d9c5
commit
40d081d3d9
17 changed files with 536 additions and 26 deletions
|
@ -18,7 +18,6 @@ import * as fetchTypes from "./web/fetch.ts";
|
|||
import * as headers from "./web/headers.ts";
|
||||
import * as navigator from "./web/navigator.ts";
|
||||
import * as permissions from "./web/permissions.ts";
|
||||
import * as performanceUtil from "./web/performance.ts";
|
||||
import type * as promiseTypes from "./web/promise.ts";
|
||||
import * as queuingStrategy from "./web/streams/queuing_strategy.ts";
|
||||
import * as readableStream from "./web/streams/readable_stream.ts";
|
||||
|
@ -29,6 +28,7 @@ import * as transformStream from "./web/streams/transform_stream.ts";
|
|||
import * as url from "./web/url.ts";
|
||||
import * as urlSearchParams from "./web/url_search_params.ts";
|
||||
import * as workers from "./web/workers.ts";
|
||||
import * as performance from "./web/performance.ts";
|
||||
import * as writableStream from "./web/streams/writable_stream.ts";
|
||||
|
||||
// These imports are not exposed and therefore are fine to just import the
|
||||
|
@ -234,12 +234,16 @@ export const windowOrWorkerGlobalScopeProperties = {
|
|||
Headers: nonEnumerable(headers.HeadersImpl),
|
||||
navigator: nonEnumerable(new navigator.NavigatorImpl()),
|
||||
Navigator: nonEnumerable(navigator.NavigatorImpl),
|
||||
performance: writable(new performanceUtil.Performance()),
|
||||
Permissions: nonEnumerable(permissions.PermissionsImpl),
|
||||
PermissionStatus: nonEnumerable(permissions.PermissionStatusImpl),
|
||||
ReadableStream: nonEnumerable(readableStream.ReadableStreamImpl),
|
||||
Request: nonEnumerable(request.Request),
|
||||
Response: nonEnumerable(fetchTypes.Response),
|
||||
performance: writable(new performance.PerformanceImpl()),
|
||||
Performance: nonEnumerable(performance.PerformanceImpl),
|
||||
PerformanceEntry: nonEnumerable(performance.PerformanceEntryImpl),
|
||||
PerformanceMark: nonEnumerable(performance.PerformanceMarkImpl),
|
||||
PerformanceMeasure: nonEnumerable(performance.PerformanceMeasureImpl),
|
||||
TextDecoder: nonEnumerable(textEncoding.TextDecoder),
|
||||
TextEncoder: nonEnumerable(textEncoding.TextEncoder),
|
||||
TransformStream: nonEnumerable(transformStream.TransformStreamImpl),
|
||||
|
|
44
cli/js/lib.deno.ns.d.ts
vendored
44
cli/js/lib.deno.ns.d.ts
vendored
|
@ -3,6 +3,9 @@
|
|||
/// <reference no-default-lib="true" />
|
||||
/// <reference lib="esnext" />
|
||||
|
||||
/** Deno provides extra properties on `import.meta`. These are included here
|
||||
* to ensure that these are still available when using the Deno namepsace in
|
||||
* conjunction with other type libs, like `dom`. */
|
||||
declare interface ImportMeta {
|
||||
/** A string representation of the fully qualified module URL. */
|
||||
url: string;
|
||||
|
@ -19,6 +22,47 @@ declare interface ImportMeta {
|
|||
main: boolean;
|
||||
}
|
||||
|
||||
/** Deno supports user timing Level 3 (see: https://w3c.github.io/user-timing)
|
||||
* which is not widely supported yet in other runtimes. These types are here
|
||||
* so that these features are still available when using the Deno namespace
|
||||
* in conjunction with other type libs, like `dom`. */
|
||||
declare interface Performance {
|
||||
/** Stores a timestamp with the associated name (a "mark"). */
|
||||
mark(markName: string, options?: PerformanceMarkOptions): PerformanceMark;
|
||||
|
||||
/** Stores the `DOMHighResTimeStamp` duration between two marks along with the
|
||||
* associated name (a "measure"). */
|
||||
measure(
|
||||
measureName: string,
|
||||
options?: PerformanceMeasureOptions
|
||||
): PerformanceMeasure;
|
||||
}
|
||||
|
||||
declare interface PerformanceMarkOptions {
|
||||
/** Metadata to be included in the mark. */
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
detail?: any;
|
||||
|
||||
/** Timestamp to be used as the mark time. */
|
||||
startTime?: number;
|
||||
}
|
||||
|
||||
declare interface PerformanceMeasureOptions {
|
||||
/** Metadata to be included in the measure. */
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
detail?: any;
|
||||
|
||||
/** Timestamp to be used as the start time or string to be used as start
|
||||
* mark.*/
|
||||
start?: string | number;
|
||||
|
||||
/** Duration between the start and end times. */
|
||||
duration?: number;
|
||||
|
||||
/** Timestamp to be used as the end time or string to be used as end mark. */
|
||||
end?: string | number;
|
||||
}
|
||||
|
||||
declare interface Permissions {
|
||||
/** Resolves to the current status of a permission.
|
||||
*
|
||||
|
|
94
cli/js/lib.deno.shared_globals.d.ts
vendored
94
cli/js/lib.deno.shared_globals.d.ts
vendored
|
@ -1337,7 +1337,36 @@ declare class Worker extends EventTarget {
|
|||
terminate(): void;
|
||||
}
|
||||
|
||||
declare namespace performance {
|
||||
declare type PerformanceEntryList = PerformanceEntry[];
|
||||
|
||||
declare interface Performance {
|
||||
/** Removes the stored timestamp with the associated name. */
|
||||
clearMarks(markName?: string): void;
|
||||
|
||||
/** Removes stored timestamp with the associated name. */
|
||||
clearMeasures(measureName?: string): void;
|
||||
|
||||
getEntries(): PerformanceEntryList;
|
||||
getEntriesByName(name: string, type?: string): PerformanceEntryList;
|
||||
getEntriesByType(type: string): PerformanceEntryList;
|
||||
|
||||
/** Stores a timestamp with the associated name (a "mark"). */
|
||||
mark(markName: string, options?: PerformanceMarkOptions): PerformanceMark;
|
||||
|
||||
/** Stores the `DOMHighResTimeStamp` duration between two marks along with the
|
||||
* associated name (a "measure"). */
|
||||
measure(
|
||||
measureName: string,
|
||||
options?: PerformanceMeasureOptions
|
||||
): PerformanceMeasure;
|
||||
/** Stores the `DOMHighResTimeStamp` duration between two marks along with the
|
||||
* associated name (a "measure"). */
|
||||
measure(
|
||||
measureName: string,
|
||||
startMark?: string,
|
||||
endMark?: string
|
||||
): PerformanceMeasure;
|
||||
|
||||
/** Returns a current time from Deno's start in milliseconds.
|
||||
*
|
||||
* Use the permission flag `--allow-hrtime` return a precise value.
|
||||
|
@ -1347,7 +1376,68 @@ declare namespace performance {
|
|||
* console.log(`${t} ms since start!`);
|
||||
* ```
|
||||
*/
|
||||
export function now(): number;
|
||||
now(): number;
|
||||
}
|
||||
|
||||
declare const Performance: {
|
||||
prototype: Performance;
|
||||
new (): Performance;
|
||||
};
|
||||
|
||||
declare const performance: Performance;
|
||||
|
||||
declare interface PerformanceMarkOptions {
|
||||
/** Metadata to be included in the mark. */
|
||||
detail?: any;
|
||||
|
||||
/** Timestamp to be used as the mark time. */
|
||||
startTime?: number;
|
||||
}
|
||||
|
||||
declare interface PerformanceMeasureOptions {
|
||||
/** Metadata to be included in the measure. */
|
||||
detail?: any;
|
||||
|
||||
/** Timestamp to be used as the start time or string to be used as start
|
||||
* mark.*/
|
||||
start?: string | number;
|
||||
|
||||
/** Duration between the start and end times. */
|
||||
duration?: number;
|
||||
|
||||
/** Timestamp to be used as the end time or string to be used as end mark. */
|
||||
end?: string | number;
|
||||
}
|
||||
|
||||
/** Encapsulates a single performance metric that is part of the performance
|
||||
* timeline. A performance entry can be directly created by making a performance
|
||||
* mark or measure (for example by calling the `.mark()` method) at an explicit
|
||||
* point in an application. */
|
||||
declare class PerformanceEntry {
|
||||
readonly duration: number;
|
||||
readonly entryType: string;
|
||||
readonly name: string;
|
||||
readonly startTime: number;
|
||||
toJSON(): any;
|
||||
}
|
||||
|
||||
/** `PerformanceMark` is an abstract interface for `PerformanceEntry` objects
|
||||
* with an entryType of `"mark"`. Entries of this type are created by calling
|
||||
* `performance.mark()` to add a named `DOMHighResTimeStamp` (the mark) to the
|
||||
* performance timeline. */
|
||||
declare class PerformanceMark extends PerformanceEntry {
|
||||
readonly detail: any;
|
||||
readonly entryType: "mark";
|
||||
constructor(name: string, options?: PerformanceMarkOptions);
|
||||
}
|
||||
|
||||
/** `PerformanceMeasure` is an abstract interface for `PerformanceEntry` objects
|
||||
* with an entryType of `"measure"`. Entries of this type are created by calling
|
||||
* `performance.measure()` to add a named `DOMHighResTimeStamp` (the measure)
|
||||
* between two marks to the performance timeline. */
|
||||
declare class PerformanceMeasure extends PerformanceEntry {
|
||||
readonly detail: any;
|
||||
readonly entryType: "measure";
|
||||
}
|
||||
|
||||
interface EventInit {
|
||||
|
|
|
@ -1,10 +1,336 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import { now as opNow } from "../ops/timers.ts";
|
||||
import { customInspect, inspect } from "./console.ts";
|
||||
import { cloneValue, setFunctionName } from "./util.ts";
|
||||
|
||||
export class Performance {
|
||||
now(): number {
|
||||
let performanceEntries: PerformanceEntryList = [];
|
||||
|
||||
function findMostRecent(
|
||||
name: string,
|
||||
type: "mark" | "measure"
|
||||
): PerformanceEntry | undefined {
|
||||
return performanceEntries
|
||||
.slice()
|
||||
.reverse()
|
||||
.find((entry) => entry.name === name && entry.entryType === type);
|
||||
}
|
||||
|
||||
function convertMarkToTimestamp(mark: string | number): number {
|
||||
if (typeof mark === "string") {
|
||||
const entry = findMostRecent(mark, "mark");
|
||||
if (!entry) {
|
||||
throw new SyntaxError(`Cannot find mark: "${mark}".`);
|
||||
}
|
||||
return entry.startTime;
|
||||
}
|
||||
if (mark < 0) {
|
||||
throw new TypeError("Mark cannot be negative.");
|
||||
}
|
||||
return mark;
|
||||
}
|
||||
|
||||
function filterByNameType(
|
||||
name?: string,
|
||||
type?: "mark" | "measure"
|
||||
): PerformanceEntryList {
|
||||
return performanceEntries.filter(
|
||||
(entry) =>
|
||||
(name ? entry.name === name : true) &&
|
||||
(type ? entry.entryType === type : true)
|
||||
);
|
||||
}
|
||||
|
||||
function now(): number {
|
||||
const res = opNow();
|
||||
return res.seconds * 1e3 + res.subsecNanos / 1e6;
|
||||
}
|
||||
|
||||
export class PerformanceEntryImpl implements PerformanceEntry {
|
||||
#name: string;
|
||||
#entryType: string;
|
||||
#startTime: number;
|
||||
#duration: number;
|
||||
|
||||
get name(): string {
|
||||
return this.#name;
|
||||
}
|
||||
|
||||
get entryType(): string {
|
||||
return this.#entryType;
|
||||
}
|
||||
|
||||
get startTime(): number {
|
||||
return this.#startTime;
|
||||
}
|
||||
|
||||
get duration(): number {
|
||||
return this.#duration;
|
||||
}
|
||||
|
||||
constructor(
|
||||
name: string,
|
||||
entryType: string,
|
||||
startTime: number,
|
||||
duration: number
|
||||
) {
|
||||
this.#name = name;
|
||||
this.#entryType = entryType;
|
||||
this.#startTime = startTime;
|
||||
this.#duration = duration;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
toJSON(): any {
|
||||
return {
|
||||
name: this.#name,
|
||||
entryType: this.#entryType,
|
||||
startTime: this.#startTime,
|
||||
duration: this.#duration,
|
||||
};
|
||||
}
|
||||
|
||||
[customInspect](): string {
|
||||
return `${this.constructor.name} { name: "${this.name}", entryType: "${this.entryType}", startTime: ${this.startTime}, duration: ${this.duration} }`;
|
||||
}
|
||||
}
|
||||
|
||||
export class PerformanceMarkImpl extends PerformanceEntryImpl
|
||||
implements PerformanceMark {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
#detail: any;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
get detail(): any {
|
||||
return this.#detail;
|
||||
}
|
||||
|
||||
get entryType(): "mark" {
|
||||
return "mark";
|
||||
}
|
||||
|
||||
constructor(
|
||||
name: string,
|
||||
{ detail = null, startTime = now() }: PerformanceMarkOptions = {}
|
||||
) {
|
||||
super(name, "mark", startTime, 0);
|
||||
if (startTime < 0) {
|
||||
throw new TypeError("startTime cannot be negative");
|
||||
}
|
||||
this.#detail = cloneValue(detail);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
toJSON(): any {
|
||||
return {
|
||||
name: this.name,
|
||||
entryType: this.entryType,
|
||||
startTime: this.startTime,
|
||||
duration: this.duration,
|
||||
detail: this.detail,
|
||||
};
|
||||
}
|
||||
|
||||
[customInspect](): string {
|
||||
return this.detail
|
||||
? `${this.constructor.name} {\n detail: ${inspect(this.detail, {
|
||||
depth: 3,
|
||||
})},\n name: "${this.name}",\n entryType: "${
|
||||
this.entryType
|
||||
}",\n startTime: ${this.startTime},\n duration: ${this.duration}\n}`
|
||||
: `${this.constructor.name} { detail: ${this.detail}, name: "${this.name}", entryType: "${this.entryType}", startTime: ${this.startTime}, duration: ${this.duration} }`;
|
||||
}
|
||||
}
|
||||
|
||||
export class PerformanceMeasureImpl extends PerformanceEntryImpl
|
||||
implements PerformanceMeasure {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
#detail: any;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
get detail(): any {
|
||||
return this.#detail;
|
||||
}
|
||||
|
||||
get entryType(): "measure" {
|
||||
return "measure";
|
||||
}
|
||||
|
||||
constructor(
|
||||
name: string,
|
||||
startTime: number,
|
||||
duration: number,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
detail: any = null
|
||||
) {
|
||||
super(name, "measure", startTime, duration);
|
||||
this.#detail = cloneValue(detail);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
toJSON(): any {
|
||||
return {
|
||||
name: this.name,
|
||||
entryType: this.entryType,
|
||||
startTime: this.startTime,
|
||||
duration: this.duration,
|
||||
detail: this.detail,
|
||||
};
|
||||
}
|
||||
|
||||
[customInspect](): string {
|
||||
return this.detail
|
||||
? `${this.constructor.name} {\n detail: ${inspect(this.detail, {
|
||||
depth: 3,
|
||||
})},\n name: "${this.name}",\n entryType: "${
|
||||
this.entryType
|
||||
}",\n startTime: ${this.startTime},\n duration: ${this.duration}\n}`
|
||||
: `${this.constructor.name} { detail: ${this.detail}, name: "${this.name}", entryType: "${this.entryType}", startTime: ${this.startTime}, duration: ${this.duration} }`;
|
||||
}
|
||||
}
|
||||
|
||||
export class PerformanceImpl implements Performance {
|
||||
clearMarks(markName?: string): void {
|
||||
if (markName == null) {
|
||||
performanceEntries = performanceEntries.filter(
|
||||
(entry) => entry.entryType !== "mark"
|
||||
);
|
||||
} else {
|
||||
performanceEntries = performanceEntries.filter(
|
||||
(entry) => !(entry.name === markName && entry.entryType === "mark")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
clearMeasures(measureName?: string): void {
|
||||
if (measureName == null) {
|
||||
performanceEntries = performanceEntries.filter(
|
||||
(entry) => entry.entryType !== "measure"
|
||||
);
|
||||
} else {
|
||||
performanceEntries = performanceEntries.filter(
|
||||
(entry) =>
|
||||
!(entry.name === measureName && entry.entryType === "measure")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
getEntries(): PerformanceEntryList {
|
||||
return filterByNameType();
|
||||
}
|
||||
getEntriesByName(
|
||||
name: string,
|
||||
type?: "mark" | "measure"
|
||||
): PerformanceEntryList {
|
||||
return filterByNameType(name, type);
|
||||
}
|
||||
getEntriesByType(type: "mark" | "measure"): PerformanceEntryList {
|
||||
return filterByNameType(undefined, type);
|
||||
}
|
||||
|
||||
mark(
|
||||
markName: string,
|
||||
options: PerformanceMarkOptions = {}
|
||||
): PerformanceMark {
|
||||
// 3.1.1.1 If the global object is a Window object and markName uses the
|
||||
// same name as a read only attribute in the PerformanceTiming interface,
|
||||
// throw a SyntaxError. - not implemented
|
||||
const entry = new PerformanceMarkImpl(markName, options);
|
||||
// 3.1.1.7 Queue entry - not implemented
|
||||
performanceEntries.push(entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
measure(
|
||||
measureName: string,
|
||||
options?: PerformanceMeasureOptions
|
||||
): PerformanceMeasure;
|
||||
measure(
|
||||
measureName: string,
|
||||
startMark?: string,
|
||||
endMark?: string
|
||||
): PerformanceMeasure;
|
||||
measure(
|
||||
measureName: string,
|
||||
startOrMeasureOptions: string | PerformanceMeasureOptions = {},
|
||||
endMark?: string
|
||||
): PerformanceMeasure {
|
||||
if (startOrMeasureOptions && typeof startOrMeasureOptions === "object") {
|
||||
if (endMark) {
|
||||
throw new TypeError("Options cannot be passed with endMark.");
|
||||
}
|
||||
if (
|
||||
!("start" in startOrMeasureOptions) &&
|
||||
!("end" in startOrMeasureOptions)
|
||||
) {
|
||||
throw new TypeError("A start or end mark must be supplied in options.");
|
||||
}
|
||||
if (
|
||||
"start" in startOrMeasureOptions &&
|
||||
"duration" in startOrMeasureOptions &&
|
||||
"end" in startOrMeasureOptions
|
||||
) {
|
||||
throw new TypeError(
|
||||
"Cannot specify start, end, and duration together in options."
|
||||
);
|
||||
}
|
||||
}
|
||||
let endTime: number;
|
||||
if (endMark) {
|
||||
endTime = convertMarkToTimestamp(endMark);
|
||||
} else if (
|
||||
typeof startOrMeasureOptions === "object" &&
|
||||
"end" in startOrMeasureOptions
|
||||
) {
|
||||
endTime = convertMarkToTimestamp(startOrMeasureOptions.end!);
|
||||
} else if (
|
||||
typeof startOrMeasureOptions === "object" &&
|
||||
"start" in startOrMeasureOptions &&
|
||||
"duration" in startOrMeasureOptions
|
||||
) {
|
||||
const start = convertMarkToTimestamp(startOrMeasureOptions.start!);
|
||||
const duration = convertMarkToTimestamp(startOrMeasureOptions.duration!);
|
||||
endTime = start + duration;
|
||||
} else {
|
||||
endTime = now();
|
||||
}
|
||||
let startTime: number;
|
||||
if (
|
||||
typeof startOrMeasureOptions === "object" &&
|
||||
"start" in startOrMeasureOptions
|
||||
) {
|
||||
startTime = convertMarkToTimestamp(startOrMeasureOptions.start!);
|
||||
} else if (
|
||||
typeof startOrMeasureOptions === "object" &&
|
||||
"end" in startOrMeasureOptions &&
|
||||
"duration" in startOrMeasureOptions
|
||||
) {
|
||||
const end = convertMarkToTimestamp(startOrMeasureOptions.end!);
|
||||
const duration = convertMarkToTimestamp(startOrMeasureOptions.duration!);
|
||||
startTime = end - duration;
|
||||
} else if (typeof startOrMeasureOptions === "string") {
|
||||
startTime = convertMarkToTimestamp(startOrMeasureOptions);
|
||||
} else {
|
||||
startTime = 0;
|
||||
}
|
||||
const entry = new PerformanceMeasureImpl(
|
||||
measureName,
|
||||
startTime,
|
||||
endTime - startTime,
|
||||
typeof startOrMeasureOptions === "object"
|
||||
? startOrMeasureOptions.detail ?? null
|
||||
: null
|
||||
);
|
||||
performanceEntries.push(entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
now(): number {
|
||||
return now();
|
||||
}
|
||||
}
|
||||
|
||||
setFunctionName(PerformanceEntryImpl, "PerformanceEntry");
|
||||
setFunctionName(PerformanceMarkImpl, "PerformanceMark");
|
||||
setFunctionName(PerformanceMeasureImpl, "PerformanceMeasure");
|
||||
setFunctionName(PerformanceImpl, "Performance");
|
||||
|
|
|
@ -19,7 +19,7 @@ import { WritableStreamDefaultWriterImpl } from "./writable_stream_default_write
|
|||
import { WritableStreamImpl } from "./writable_stream.ts";
|
||||
import { AbortSignalImpl } from "../abort_signal.ts";
|
||||
import { DOMExceptionImpl as DOMException } from "../dom_exception.ts";
|
||||
import { cloneValue } from "../util.ts";
|
||||
import { cloneValue, setFunctionName } from "../util.ts";
|
||||
import { assert, AssertionError } from "../../util.ts";
|
||||
|
||||
export type AbortAlgorithm = (reason?: any) => PromiseLike<void>;
|
||||
|
@ -1320,12 +1320,6 @@ export function resetQueue<R>(container: Container<R>): void {
|
|||
container[sym.queueTotalSize] = 0;
|
||||
}
|
||||
|
||||
/** An internal function which provides a function name for some generated
|
||||
* functions, so stack traces are a bit more readable. */
|
||||
export function setFunctionName(fn: Function, value: string): void {
|
||||
Object.defineProperty(fn, "name", { value, configurable: true });
|
||||
}
|
||||
|
||||
/** An internal function which mimics the behavior of setting the promise to
|
||||
* handled in JavaScript. In this situation, an assertion failure, which
|
||||
* shouldn't happen will get thrown, instead of swallowed. */
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import { setFunctionName } from "./internals.ts";
|
||||
import { customInspect } from "../console.ts";
|
||||
import { setFunctionName } from "../util.ts";
|
||||
|
||||
export class CountQueuingStrategyImpl implements CountQueuingStrategy {
|
||||
highWaterMark: number;
|
||||
|
|
|
@ -18,12 +18,12 @@ import {
|
|||
readableStreamHasDefaultReader,
|
||||
readableStreamGetNumReadRequests,
|
||||
readableStreamCreateReadResult,
|
||||
setFunctionName,
|
||||
} from "./internals.ts";
|
||||
import type { ReadableStreamImpl } from "./readable_stream.ts";
|
||||
import * as sym from "./symbols.ts";
|
||||
import { assert } from "../../util.ts";
|
||||
import { customInspect } from "../console.ts";
|
||||
import { setFunctionName } from "../util.ts";
|
||||
|
||||
export class ReadableByteStreamControllerImpl
|
||||
implements ReadableByteStreamController {
|
||||
|
|
|
@ -9,7 +9,6 @@ import {
|
|||
isWritableStream,
|
||||
isWritableStreamLocked,
|
||||
makeSizeAlgorithmFromSizeFunction,
|
||||
setFunctionName,
|
||||
setPromiseIsHandledToTrue,
|
||||
readableStreamCancel,
|
||||
ReadableStreamGenericReader,
|
||||
|
@ -25,6 +24,7 @@ import type { ReadableStreamDefaultControllerImpl } from "./readable_stream_defa
|
|||
import * as sym from "./symbols.ts";
|
||||
import { customInspect } from "../console.ts";
|
||||
import { AbortSignalImpl } from "../abort_signal.ts";
|
||||
import { setFunctionName } from "../util.ts";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export class ReadableStreamImpl<R = any> implements ReadableStream<R> {
|
||||
|
|
|
@ -18,11 +18,11 @@ import {
|
|||
readableStreamDefaultControllerGetDesiredSize,
|
||||
resetQueue,
|
||||
SizeAlgorithm,
|
||||
setFunctionName,
|
||||
} from "./internals.ts";
|
||||
import type { ReadableStreamImpl } from "./readable_stream.ts";
|
||||
import * as sym from "./symbols.ts";
|
||||
import { customInspect } from "../console.ts";
|
||||
import { setFunctionName } from "../util.ts";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export class ReadableStreamDefaultControllerImpl<R = any>
|
||||
|
|
|
@ -9,11 +9,11 @@ import {
|
|||
readableStreamReaderGenericCancel,
|
||||
readableStreamReaderGenericInitialize,
|
||||
readableStreamReaderGenericRelease,
|
||||
setFunctionName,
|
||||
} from "./internals.ts";
|
||||
import type { ReadableStreamImpl } from "./readable_stream.ts";
|
||||
import * as sym from "./symbols.ts";
|
||||
import { customInspect } from "../console.ts";
|
||||
import { setFunctionName } from "../util.ts";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export class ReadableStreamDefaultReaderImpl<R = any>
|
||||
|
|
|
@ -7,7 +7,6 @@ import {
|
|||
invokeOrNoop,
|
||||
isTransformStream,
|
||||
makeSizeAlgorithmFromSizeFunction,
|
||||
setFunctionName,
|
||||
setUpTransformStreamDefaultControllerFromTransformer,
|
||||
validateAndNormalizeHighWaterMark,
|
||||
} from "./internals.ts";
|
||||
|
@ -16,6 +15,7 @@ import * as sym from "./symbols.ts";
|
|||
import type { TransformStreamDefaultControllerImpl } from "./transform_stream_default_controller.ts";
|
||||
import type { WritableStreamImpl } from "./writable_stream.ts";
|
||||
import { customInspect, inspect } from "../console.ts";
|
||||
import { setFunctionName } from "../util.ts";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export class TransformStreamImpl<I = any, O = any>
|
||||
|
|
|
@ -4,7 +4,6 @@ import {
|
|||
FlushAlgorithm,
|
||||
isTransformStreamDefaultController,
|
||||
readableStreamDefaultControllerGetDesiredSize,
|
||||
setFunctionName,
|
||||
TransformAlgorithm,
|
||||
transformStreamDefaultControllerEnqueue,
|
||||
transformStreamDefaultControllerError,
|
||||
|
@ -14,6 +13,7 @@ import type { ReadableStreamDefaultControllerImpl } from "./readable_stream_defa
|
|||
import * as sym from "./symbols.ts";
|
||||
import type { TransformStreamImpl } from "./transform_stream.ts";
|
||||
import { customInspect } from "../console.ts";
|
||||
import { setFunctionName } from "../util.ts";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export class TransformStreamDefaultControllerImpl<I = any, O = any>
|
||||
|
|
|
@ -8,7 +8,6 @@ import {
|
|||
isWritableStream,
|
||||
isWritableStreamLocked,
|
||||
makeSizeAlgorithmFromSizeFunction,
|
||||
setFunctionName,
|
||||
setUpWritableStreamDefaultControllerFromUnderlyingSink,
|
||||
writableStreamAbort,
|
||||
writableStreamClose,
|
||||
|
@ -19,6 +18,7 @@ import * as sym from "./symbols.ts";
|
|||
import type { WritableStreamDefaultControllerImpl } from "./writable_stream_default_controller.ts";
|
||||
import type { WritableStreamDefaultWriterImpl } from "./writable_stream_default_writer.ts";
|
||||
import { customInspect } from "../console.ts";
|
||||
import { setFunctionName } from "../util.ts";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export class WritableStreamImpl<W = any> implements WritableStream<W> {
|
||||
|
|
|
@ -6,7 +6,6 @@ import {
|
|||
isWritableStreamDefaultController,
|
||||
Pair,
|
||||
resetQueue,
|
||||
setFunctionName,
|
||||
SizeAlgorithm,
|
||||
WriteAlgorithm,
|
||||
writableStreamDefaultControllerClearAlgorithms,
|
||||
|
@ -15,6 +14,7 @@ import {
|
|||
import * as sym from "./symbols.ts";
|
||||
import type { WritableStreamImpl } from "./writable_stream.ts";
|
||||
import { customInspect } from "../console.ts";
|
||||
import { setFunctionName } from "../util.ts";
|
||||
|
||||
export class WritableStreamDefaultControllerImpl<W>
|
||||
implements WritableStreamDefaultController {
|
||||
|
|
|
@ -6,7 +6,6 @@ import {
|
|||
isWritableStream,
|
||||
isWritableStreamDefaultWriter,
|
||||
isWritableStreamLocked,
|
||||
setFunctionName,
|
||||
setPromiseIsHandledToTrue,
|
||||
writableStreamCloseQueuedOrInFlight,
|
||||
writableStreamDefaultWriterAbort,
|
||||
|
@ -19,6 +18,7 @@ import * as sym from "./symbols.ts";
|
|||
import type { WritableStreamImpl } from "./writable_stream.ts";
|
||||
import { customInspect } from "../console.ts";
|
||||
import { assert } from "../../util.ts";
|
||||
import { setFunctionName } from "../util.ts";
|
||||
|
||||
export class WritableStreamDefaultWriterImpl<W>
|
||||
implements WritableStreamDefaultWriter<W> {
|
||||
|
|
|
@ -208,3 +208,11 @@ export function getHeaderValueParams(value: string): Map<string, string> {
|
|||
export function hasHeaderValueOf(s: string, value: string): boolean {
|
||||
return new RegExp(`^${value}[\t\s]*;?`).test(s);
|
||||
}
|
||||
|
||||
/** An internal function which provides a function name for some generated
|
||||
* functions, so stack traces are a bit more readable.
|
||||
*
|
||||
* @internal */
|
||||
export function setFunctionName(fn: Function, value: string): void {
|
||||
Object.defineProperty(fn, "name", { value, configurable: true });
|
||||
}
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
import { unitTest, assert, createResolvable } from "./test_util.ts";
|
||||
import {
|
||||
unitTest,
|
||||
assert,
|
||||
assertEquals,
|
||||
createResolvable,
|
||||
} from "./test_util.ts";
|
||||
|
||||
unitTest({ perms: { hrtime: false } }, async function performanceNow(): Promise<
|
||||
void
|
||||
|
@ -13,3 +18,42 @@ unitTest({ perms: { hrtime: false } }, async function performanceNow(): Promise<
|
|||
}, 10);
|
||||
await resolvable;
|
||||
});
|
||||
|
||||
unitTest(function performanceMark() {
|
||||
const mark = performance.mark("test");
|
||||
assert(mark instanceof PerformanceMark);
|
||||
assertEquals(mark.detail, null);
|
||||
assertEquals(mark.name, "test");
|
||||
assertEquals(mark.entryType, "mark");
|
||||
assert(mark.startTime > 0);
|
||||
assertEquals(mark.duration, 0);
|
||||
const entries = performance.getEntries();
|
||||
assert(entries[entries.length - 1] === mark);
|
||||
const markEntries = performance.getEntriesByName("test", "mark");
|
||||
assert(markEntries[markEntries.length - 1] === mark);
|
||||
});
|
||||
|
||||
unitTest(function performanceMeasure() {
|
||||
const mark = performance.mark("test");
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
try {
|
||||
const measure = performance.measure("test", "test");
|
||||
assert(measure instanceof PerformanceMeasure);
|
||||
assertEquals(measure.detail, null);
|
||||
assertEquals(measure.name, "test");
|
||||
assertEquals(measure.entryType, "measure");
|
||||
assert(measure.startTime > 0);
|
||||
assertEquals(mark.startTime, measure.startTime);
|
||||
assert(measure.duration >= 100 && measure.duration < 200);
|
||||
const entries = performance.getEntries();
|
||||
assert(entries[entries.length - 1] === measure);
|
||||
const measureEntries = performance.getEntriesByName("test", "measure");
|
||||
assert(measureEntries[measureEntries.length - 1] === measure);
|
||||
} catch (e) {
|
||||
return reject(e);
|
||||
}
|
||||
resolve();
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue