Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ An instance object used to access the results of the speedtest measurements. The
| **getUploadBandwidthPoints()** | Returns an array with all the upload measurement results. Each item will include the following fields: `{ bytes, bps, duration, ping, measTime, serverTime, transferSize }`. |
| **getPacketLoss()** | Returns the reduced value of the measured packet loss ratio (between 0 and 1). Requires a `packetLoss` measurement set. |
| **getPacketLossDetails()** | Returns an object with the details of the packet loss measurement. Includes the following fields: `{ packetLoss, totalMessages, numMessagesSent, lostMessages }`. Requires a `packetLoss` measurement set. |
| **getTotalDurationMs()** | Returns the total time (in milliseconds) the engine spent running, excluding any time spent paused. Only available after the engine has finished. |
| **getScores()** | Returns the computed [AIM scores](https://developers.cloudflare.com/fundamentals/speed/aim/) that categorize the quality of the network connection according to use cases such as streaming, gaming or real-time communications. This score is only available after the engine has finished performing all of the measurements. |

[npm-img]: https://img.shields.io/npm/v/@cloudflare/speedtest
Expand Down
12 changes: 9 additions & 3 deletions src/Results/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@ class Results {
raw;

get isFinished() {
return Object.values(this.raw).every(d => d.finished);
return Object.values(this.raw)
.filter(d => d && typeof d === 'object')
.every(d => d.finished);
}

// Public methods
clear() {
this.raw = Object.assign(
{},
{
totalDurationMs: undefined
},
...[...new Set(this.#config.measurements.map(m => m.type))].map(m => ({
[m]: { started: false, finished: false, results: {} }
}))
Expand Down Expand Up @@ -47,6 +51,7 @@ class Results {
getPacketLoss = () => this.#calcGetter('getPacketLoss', 'packetLoss');
getPacketLossDetails = () =>
this.#calcGetter('getPacketLossDetails', 'packetLoss', undefined, true);
getTotalDurationMs = () => this.raw.totalDurationMs;

getSummary() {
const items = {
Expand All @@ -60,7 +65,8 @@ class Results {
upLoadedJitter: this.getUpLoadedJitter,
packetLoss: this.getPacketLoss,
v4Reachability: this.#getV4Reachability,
v6Reachability: this.#getV6Reachability
v6Reachability: this.#getV6Reachability,
totalDurationMs: this.getTotalDurationMs
};

return Object.assign(
Expand Down
2 changes: 2 additions & 0 deletions src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export declare class Results {
upLoadedLatency?: number,
upLoadedJitter?: number,
packetLoss?: number,
totalDurationMs?: number,
}

getUnloadedLatency: () => number | undefined;
Expand All @@ -90,6 +91,7 @@ export declare class Results {
numMessagesSent: number,
lostMessages: number[]
} | { error: string } | undefined;
getTotalDurationMs: () => number | undefined;

getScores: () => {
[key: string]: {
Expand Down
31 changes: 30 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,22 @@ class MeasurementEngine {
#optimalDownloadChunkSize = DEFAULT_OPTIMAL_DOWNLOAD_SIZE;
#optimalUploadChunkSize = DEFAULT_OPTIMAL_UPLOAD_SIZE;

/**
* High-resolution timestamp (from performance.now()) of the test start or
* last unpause. Used to calculate totalDurationMs in the final results.
*
* @type {number | undefined}
*/
#startTime;

/**
* Accumulated time running the test (unpaused), in milliseconds.
* Used to calculate totalDurationMs in the final results.
*
* @type {number}
*/
#accumulatedRuntimeMs = 0;

#running = false;
#finished = false;

Expand All @@ -93,12 +109,24 @@ class MeasurementEngine {
this.#running = running;
this.onRunningChange(this.#running);
}

if (running) {
this.#startTime = performance.now();
} else {
if (typeof this.#startTime !== 'undefined') {
this.#accumulatedRuntimeMs += performance.now() - this.#startTime;
this.#startTime = undefined;
}
}
}

#setFinished(finished) {
if (finished !== this.#finished) {
this.#finished = finished;
finished && setTimeout(() => this.#onFinish(this.results));
if (finished) {
this.#results.raw.totalDurationMs = this.#accumulatedRuntimeMs;
setTimeout(() => this.#onFinish(this.results));
}
}
}

Expand All @@ -124,6 +152,7 @@ class MeasurementEngine {
this.#setFinished(false);

this.#results.clear();
this.#accumulatedRuntimeMs = 0;
}

#destroyCurEngine() {
Expand Down
3 changes: 2 additions & 1 deletion src/logging/logFinalResults.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ const resultsParsers = {
upload: ['getUploadBandwidthPoints', bpsPointsParser],
downLoadedLatencyMs: ['getDownLoadedLatencyPoints', latencyPointsParser],
upLoadedLatencyMs: ['getUpLoadedLatencyPoints', latencyPointsParser],
packetLoss: ['getPacketLossDetails', packetLossParser]
packetLoss: ['getPacketLossDetails', packetLossParser],
totalDurationMs: ['getTotalDurationMs']
// v4Reachability: ['getV4ReachabilityDetails'],
// v6Reachability: ['getV6ReachabilityDetails']
};
Expand Down
Loading