Можно ли поделиться константой с областью вне блока или замыкания

Возьмем эту примерную функцию

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

Представьте, что я заметил, что fetchData работает медленно, и я хочу быстро профилировать с помощью общей функции/генератора таймера:

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

Теперь это ломает код, так как res больше не определено. Я мог бы определить let res перед блоком или использовать var, но это означает изменение исходного кода для некоторого временного кода профилирования. Я предполагаю, что именно в этом заключается смысл const в том, что переход к заявления. Тем не менее, я все еще чувствую, что есть способ сохранить объем и вызвать событие до и после набора строк?

Я не женат на генераторах. Замыкания могут выполнять ту же работу, но иметь ту же проблему с областью действия. Другие предложения по синтаксису приветствуются.

Как я могу обернуть произвольный блок кода, но сохранить переменную область видимости? Может быть, с прокси? Что-то похожее на контекстные менеджеры из python. Это может быть на грани ограничений языка?


person david_adler    schedule 02.02.2018    source источник
comment
похоже, вы можете использовать функцию профилирования, которая принимает обратный вызов или обещание и возвращает результат   -  person Slai    schedule 02.02.2018
comment
Вы уже определили два решения (предопределить с помощью let или использовать var). Если вы перемещаете объявление let или const внутрь блока, вы сужаете его область действия только до этого блока. Обойти это невозможно - это определение языка. Обернув его в блок, вы сузили область переменных, определенных в этом блоке, с помощью const или let. Обойти это без изменения кода внутри блока невозможно.   -  person jfriend00    schedule 02.02.2018
comment
Обратите внимание, что реализация таймера профилирования в качестве генератора была бы огромной ошибкой. Генераторные функции несут огромную потерю производительности из-за характера их прерываемого потока управления. Если вы мне не верите, попробуйте сравнить функцию-генератор с эквивалентным циклом for.   -  person Patrick Roberts    schedule 02.02.2018
comment
@PatrickRoberts это только для профилирования, поэтому он почти никогда не будет запущен в производство. Генератор достаточно быстр для моих требований. Однако я открыт для любого другого синтаксиса. Я не женат на генераторах, обратных вызовах или блоках   -  person david_adler    schedule 02.02.2018
comment
Я не вижу проблем с использованием var, но я предполагаю, что должны быть различные параметры профилирования, которые не требуют каких-либо изменений кода.   -  person Slai    schedule 02.02.2018


Ответы (2)


Что вы думаете о чем-то подобном?

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
}
person bgschiller    schedule 02.02.2018
comment
Это не сработает, потому что вы вызвали fetchData перед timed, а также я хочу, чтобы это работало для произвольного количества строк. - person david_adler; 02.02.2018
comment
Поскольку fetchData — это промис, он, скорее всего, вернется сразу. Если вы хотите захватить несколько, вы можете просто обернуть их в асинхронную анонимную функцию. Однако вы сможете получить только одно возвращаемое значение. - person bgschiller; 02.02.2018
comment
Кроме того, performance.now() имеет разрешение в микросекундах (возвращается как миллисекундное значение с плавающей запятой), а Date.now() имеет только (ненадежное) разрешение в миллисекундах. - person Patrick Roberts; 02.02.2018

Я понятия не имею, что вы подразумеваете под "быстро профилировать fetchData с помощью универсальной функции/генератора таймера". Все, что я вижу, это то, что вы переместили оператор в цикл, где, очевидно, он может выполняться несколько раз или не выполняться вообще, поэтому вы не можете легко присвоить одно значение результата переменной res внешней области.

Если вы хотите использовать цикл для какой-либо структуры данных, просто используйте let res и получите последнее значение из цикла (или начальное значение, если тело цикла не запустилось).

Если вы хотите профилировать функцию fetchData, посмотрите Как измерить время выполнения промиса?.

person Bergi    schedule 03.02.2018