
Vivien Adnot
Ich versuche, eine Funktion zu schreiben, die die Ausführungszeit einer anderen Funktion misst:
export class Profiler {
public measureSyncFunc(fn: () => any): Promise<number> {
return new Promise<number>((resolve, reject) => {
let elapsed = 0;
let intervalId = window.setInterval(() => {
elapsed += 1; // this is never called
}, 1);
this.execFunc(fn)
.then((result: any) => {
window.clearInterval(intervalId);
resolve(elapsed);
});
});
}
private execFunc(fn: () => any): Promise<any> {
return new Promise<any>((resolve, reject) => {
resolve(fn());
});
}
}
Dann benutze ich es so:
let array = generateRandomArray(100000);
instance.measureSyncFunc(bubbleSort(array))
.then((elapsed: number) => {
console.log(`end session: ${elapsed} seconds`);
resolve();
});
Die BubbleSort-Funktion ist synchron und es dauert einige Sekunden, bis sie abgeschlossen ist. Siehe Code hier:
Das Ergebnis in der Konsole ist “Ende Sitzung: 0 Sekunden”, da der Intervall-Callback nie aufgerufen wird.
Weißt du, wie ich es anrufen kann? Vielen Dank Jungs!

toskv
Wenn die Funktionen, die Sie messen möchten, immer synchron sind, müssen Sie wirklich keine Versprechungen machen.
Da die Funktion, die Sie testen möchten, Parameter benötigt, packen Sie sie am besten in eine Pfeilfunktion, um sie mit einem anderen Kontext aufrufen zu können und ihre Parameter nicht selbst verwalten zu müssen.
Etwas Einfaches wie dieses wird gut tun.
function measure(fn: () => void): number {
let start = performance.now();
fn();
return performance.now() - start;
}
function longRunningFunction(n: number) {
for (let i = 0; i < n; i++) {
console.log(i);
}
}
let duration = measure(() => {
longRunningFunction(100);
});
console.log(`took ${duration} ms`);
Wenn Sie die Zeit messen möchten, die eine asynchrone Funktion (wenn sie ein Versprechen zurückgibt) zum Auflösen benötigt, können Sie den Code einfach in etwa so ändern:
function measurePromise(fn: () => Promise<any>): Promise<number> {
let onPromiseDone = () => performance.now() - start;
let start = performance.now();
return fn().then(onPromiseDone, onPromiseDone);
}
function longPromise(delay: number) {
return new Promise<string>((resolve) => {
setTimeout(() => {
resolve('Done');
}, delay);
});
}
measurePromise(() => longPromise(300))
.then((duration) => {
console.log(`promise took ${duration} ms`);
});
Hinweis: Diese Lösung verwendet den ES6 Versprechenwenn Sie etwas anderes verwenden, müssen Sie es möglicherweise anpassen, aber die Logik sollte dieselbe sein.
Sie können beide Beispiele im Playground sehen hier.
Nicht verwenden setInterval
um Millisekunden zu zählen (es ist ungenau, verzögert, driftet und hat ein Mindestintervall von etwa 4 ms). Holen Sie sich einfach zwei Zeitstempel vor und nach der Ausführung.
function measureASyncFunc(fn: () => Promise<any>): Promise<number> {
const start = Date.now();
return fn.catch(() => {}).then(() => {
const end = Date.now();
const elapsed = end-start;
return elapsed;
});
}
Für höhere Genauigkeit ersetzen Date.now
durch performance.now
.
Schau mal rein timeFnPromise und das verwandte Testfälle.
- Die Zielfunktion wird umschlossen und ausgeführt, wenn die umschlossene Funktion aufgerufen wird
- Hängt Erfüllungs-/Ablehnungs-Handler an das zugrunde liegende Promise an, das den Rückgabewert der Zielfunktionen als „ret“ und die verstrichene Zeit als „elapsedTime“ zurückgibt.
- unterstützt Argumente, indem es sie an die Zielfunktion weiterleitet
Beispielverwendung:
const wrappedFn = timeFnPromise(aFunctionThatReturnsAPromise)
wrappedFn()
.then((values)=>{
const {ret, elapsedTime} = values
console.log(`ret:[${ret}] elapsedTime:[${elapsedTime}]`)
})
Auch über das NPM-Modul verfügbar jschest.
Hier ist eine einfache Wrapper-Funktion, die ich geschrieben habe. Es gibt ein Promise (über das Schlüsselwort async) zurück, sodass Sie es einfach mit Ihrem Promise aufrufen können. Ich habe den Zeitwert als Eigenschaft zur Antwort hinzugefügt. Wenn Sie diesen Wert nicht in der Antwort haben können, müssen Sie ihn anschließend entfernen.
const stopwatchWrapper = async (promise) => {
const startTime = Date.now()
const resp = await promise
resp.executionTime = Date.now() - startTime
return resp
}
const axiosPromise = stopwatchWrapper(axios(reqSelected))
const response = await axiosPromise
console.log(response.executionTime)
Es wäre gut klarzustellen, dass die vorgeschlagenen Ansätze von toskv nur mit der Auflösung eines einzigen Versprechens funktionieren. Wenn wir Promise.all() verwenden wollen, ist das zurückgegebene Zeitergebnis falsch.
Hier ist ein Beispiel mit dem von toskv entwickelten Code, aber mit Promise.all()
Messen mit Promise.all()
Wenn jemand die Zeit messen muss, die benötigt wird, um jedes der mit Promise.all() ausgeführten Versprechen auszuführen, besteht der Ansatz darin, die Interzeptoren zu verwenden und dort die Zeitmessungen durchzuführen
10160300cookie-checkWie misst man die Ausführungszeit eines Versprechens?yes
=+
ist ein ungültiger Operator– charlietfl
24. Mai 2017 um 12:12 Uhr
Hinweis
instance.measureSyncFunc(bubbleSort(array))
Sie passieren die Ergebnis des Anrufs bubbleSort zu IhremmeasureSyncFunc
abermeasureSyncFunc
erwartet eine Funktion als Argument– Jaromanda X
24. Mai 2017 um 12:12 Uhr
setInterval
von 1 ms – ein so kleines Intervall ist eigentlich nicht möglich – haben Sie die heutzutage in den meisten Browsern verfügbaren Profiling-Tools in Betracht gezogen?performance.now()
oderconsole.time('xxx') / console.timeEnd('xxx')
– Jaromanda X
24. Mai 2017 um 12:14 Uhr
@charlietfl
invalid operator
– eigentlich würde das dazu führenelapsed == 1
dauerhaft :p– Jaromanda X
24. Mai 2017 um 12:17 Uhr