Во время выполнения урока по React ToolKit createAsyncThunk()
мне дали инструкции составить асинхронную функцию обратного вызова, которую она принимает в качестве второго аргумента. Это приближение кода:
async () => { const response = await fetchUsers(); return await response.json(); }
Роль этой функции обратного вызова заключается в предоставлении свойства полезной нагрузки действия для отправки в хранилище Redux для изменения состояния. В этом случае я извлекал список пользователей, чтобы передать их в качестве полезной нагрузки. fetchUsers()
извлекает данные из API; затем данные преобразуются в объект JavaScript с помощью json()
перед возвратом примечания.
После написания этой функции IDE, которую я использовал, выдала эту ошибку: «Совместное использование return
и await
неэффективно и следует избегать. Вместо этого вам следует разделить свои утверждения await
и return
».
Я переписал функцию в соответствии с инструкциями, возвращая переменную вместо оператора await
:
async () => { const response = await fetchUsers(); const users = await response.json(); return users; }
Это удовлетворило тестовую среду, но мне было любопытно: почему возвращаемый оператор await
заметно отличался по эффективности от возвращаемого значения переменной, присвоенной возвращаемому значению того же самого оператора await
?
Чтобы перейти к делу: заметной разницы нет. Источником этой директивы, вероятно, является документация для ESLint, в которой есть правило без ожидания возврата; он выдаст ошибку, если await
встречается в операторе return
в вашем коде. Вы можете обойти это правило, как я сделал выше, разделив return
и await
на отдельные операторы. Однако это не существенно повысит эффективность.
На самом деле, если эффективность действительно важна при работе с асинхронной функцией, в приведенных выше примерах следует вообще отказаться от второго оператора await
:
async () => { const response = await fetchUsers(); return response.json(); }
Учитывая, что асинхронные функции всегда возвращают обещание, второй оператор await
по существу является избыточным. Если значение, возвращаемое вторым оператором await
, все равно будет заключено в промис, добавляется шаг путем await
-обработки возвращаемого значения response.json()
вместо простого возврата самого выражения (поскольку .json()
является асинхронной функцией, она возвращает промис) . Это очень полезная демонстрация дополнительной работы по возврату оператора await
.
По сути, это то, что правило ESLint пытается воспрепятствовать. Но здесь важно отметить, что все вышеупомянутые варианты одной и той же асинхронной функции будут работать правильно; все они вернут обещание, которое разрешается в список объектов пользователей. И, если производительность не является первоочередной задачей (в этом случае она, вероятно, не должна быть), есть преимущество в возврате инструкции await
. Таким образом, он добавляется в трассировку стека, потенциально избавляя от головной боли, если это часть большого проекта и требуется отладка. По сути, это хорошая защитная мера с, вероятно, очень незначительным компромиссом в эффективности.
Подводя итог: для большинства практических целей, вероятно, предпочтительнее игнорировать ESLint и возвращать этот оператор await
.
использованная литература
- ESLint-документация
- Почему использование return await — плохая идея?
- Веб-документы MDN по асинхронным функциям
- Спасибо также Крису Мэддерну и Джошу Голдбергу.