0

Take this example function

async function foo () {
  const res = await fetchData()
  const out = await processData(res)
  return out
}

Imagine that I notice fetchData is slow and I want to quickly profile with a generic timer function / generator:

async function foo () {
  for (let time of timer()) {
    const res = await fetchData()
  }
  const out = await processData(res) // error res is undefined
  return out
}

This now breaks the code as res is no longer defined. I could define let res before the block, or use var but that means modifying source code for some temporary profiling code. I guess this is the very point of const is scoping to statements. However, I still feel there is a way of maintaining scope and triggering an event before and after a set of lines?

I am not married to generators. Closures could do the same job but have the same scoping issue. Other syntax suggestions welcome.

How can I wrap some arbitrary block of code but maintain the variable scope? Maybe with a proxy? Something similar to context managers from python. This could be on the edge of the limitations of the language?

david_adler
  • 9,690
  • 6
  • 57
  • 97
  • 1
    seems like you can use profiling function that accepts a callback or promise and returns it's result – Slai Feb 02 '18 at 18:35
  • 1
    You've already identified the two solutions (predefine with `let` or use `var`). If you move a `let` or `const` declaration inside a block, you narrowed its scope to only that block. There's no way around that - that's the language definition. By wrapping it in a block, you narrowed the scope of the variables defined in that block with `const` or `let`. No way around that without changing the code inside the block. – jfriend00 Feb 02 '18 at 18:38
  • 1
    Note that implementing a profiling timer as a generator would be a huge mistake. Generator functions incur a huge performance loss due to the nature of their interruptable control-flow. If you don't believe me, try benchmarking a generator function vs. an equivalent for loop. – Patrick Roberts Feb 02 '18 at 18:44
  • @PatrickRoberts this is just for profiling so it will almost never be in production. A generator is fast enough for my requirements. However I am open to any other syntax. I am not married to generators, callbacks or blocks – david_adler Feb 02 '18 at 19:05
  • I don't see an issue with using `var`, but I am guessing there must be various profiling options that don't require any code changes – Slai Feb 02 '18 at 19:49

2 Answers2

0

What do you think of something like this?

async function timed(p) {
  const start = performance.now();
  const res = await p();
  const end = performance.now();
  console.log('time elapsed', end - start);
  return res;
}

async function foo () {
  const res = await timed(fetchData);
  const out = await processData(res);
  return out
}
bgschiller
  • 2,087
  • 1
  • 16
  • 30
  • 1
    That won't work because you called `fetchData` before `timed` and also I want this to work for an arbitrary number of lines – david_adler Feb 02 '18 at 19:11
  • 1
    Since `fetchData` is a promise, it likely returns right away. If you want to capture multiple, you can just wrap them in an async anonymous function. You'll only be able to get a single return value though. – bgschiller Feb 02 '18 at 19:14
  • `fetchData()` -> `fetchData`, `await p` -> `await p()` – Patrick Roberts Feb 02 '18 at 19:33
  • Also, `performance.now()` has microsecond resolution (returned as a floating-point millisecond value) while `Date.now()` only has (unreliable) millisecond resolution. – Patrick Roberts Feb 02 '18 at 19:34
0

I have no idea what you mean by "quickly profile fetchData with a generic timer function / generator". All I can see is that you moved the statement into a loop, where obviously it might be executed multiple times or not at all, so you cannot easily assign one result value to an outer-scope res variable.

If you want to use a loop over some data structure, yes just use let res and get the last value from the loop (or the initial value in case the loop body didn't run).

If you want to profile the fetchData function, have a look at How to measure the execution time of a promise?.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375