TypeScript: ключевое слово arguments в асинхронных функциях - PullRequest
1 голос
/ 27 июня 2019

Рассмотрим следующее странное поведение, которое я заметил в одном из моих проектов:

async function hello() {
  return arguments;
}

Если для цели компиляции TypeScript установлено значение es3 или es5, вышеуказанный файл не может быть скомпилирован со следующей ошибкой:

error TS2522: The 'arguments' object cannot be referenced in an async function or method in ES3 and ES5. Consider using a standard function or method.

2   return arguments;
           ~~~~~~~~~

Однако при более высокой цели компиляции (я тестировал es2017 и esnext) ошибки нет.


Что такое ключевое слово arguments, которое не позволяет использовать его в асинхронных функциях, если для цели компиляции TypeScript установлено значение es3 или es5?

Несколько заметок:

  • При репликации в современном JavaScript эта функция не выдает исключение
  • Это поведение может быть воспроизведено только в async функциях

Моя гипотеза

Я подозреваю, что, поскольку Promise необходимо заполнить в es3 и es5, поли заполнение не может поддерживать arguments, поскольку оно зависит от вызываемой функции.

Дополнительное чтение: ES5.1 Spec § 10.6 Аргументы Объект

Ответы [ 3 ]

2 голосов
/ 27 июня 2019

Это связано с тем, что функции Async переносятся в базовую полиформатную реализацию генераторов;эта реализация в основном заменяет тело вашей функции, чтобы обернуть ее в другую функцию, поэтому любое использование arguments никогда не получит доступ к исходному arguments hello, но вместо __generator

Примером этогониже, где hello, который не принимает аргументов и генерирует следующее, в котором тело функции помещается в другую функцию.

async function hello() {
    console.log(arguments);
} // becomes.....


function hello() {
    return __awaiter(this, arguments, void 0, function () {
        return __generator(this, function (_a) {
            console.log(arguments);
            return [2 /*return*/];
        });
    });
}

для повторного выполнения, console.log (arguments) перемещено из контекстаПривет в контексте __generator означает, что он никогда не будет вести себя так, как вы ожидаете.Если вы ориентируетесь на современные браузеры (не IE), вы можете установить в качестве цели компиляции ES6 +, и в этом случае это ограничение будет снято.

1 голос
/ 28 июня 2019

Просто используйте оператор распространения

hello(...args: any[])

, теперь у вас есть массив или аргументы, которые были переданы.

0 голосов
/ 27 июня 2019

Вы абсолютно правы.

Я хотел бы поделиться другой точкой зрения о том, почему это не работает:

JavaScript имеет параллелизм на основе задач, что означает, что код разбит на маленькие «куски» (задачи)и один из них исполняется одновременно.Если у вас есть что-то асинхронное, которое разделено на несколько задач: одно для запуска асинхронного действия и одно для работы с результатами после выполнения асинхронного действия.В то же время могут выполняться другие задачи, что обеспечивает параллелизм.

Теперь наименьший возможный фрагмент выполнения был (до async) функцией: функция всегда выполняется до завершения, вы не можете разделитьфункция в несколько задач.

С введением ключевого слова async есть функции async, которые не выполняются до конца.Они будут разбиты на более мелкие задачи (через await с).

Теперь, если вам нужно перевести async function в обычный function, у вас есть одна проблема: вы не можете разделить задачи.Следовательно, вам нужно несколько функций для представления одной async function:

   async function(arg) { await a(); await b(); }
   // becomes
   function(arg) { return a().then(function () { b(); }); }

Теперь, как можно видеть, это не происходит точно: хотя arg был аргументом единственной async функции, только внешняяфункция имеет это arg.Однако, как правило, это не проблема, если вы получаете доступ к arg в текущей области или во внешней области, это не меняет способ работы (за исключением того, что вы переименовываете его).

Однако есть одна вещь, которая была изменена и которая составила этот ответ: arguments.Поскольку у нас есть две функции, у нас есть два arguments объекта.Теперь можно также имитировать объект arguments, но тогда вам придется использовать другие неподдерживаемые новые языковые функции (геттеры / сеттеры, прокси).И, честно говоря: вы не должны использовать arguments, поэтому его перенос не стоит.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...