Теорія
Власні asyncфункції можуть бути ідентифіковані при перетворенні в рядки :
asyncFn[Symbol.toStringTag] === 'AsyncFunction'
Або за AsyncFunctionконструктором:
const AsyncFunction = (async () => {}).constructor;
asyncFn instanceof AsyncFunction === true
Це не буде працювати з вихідними даними Babel / TypeScript, оскільки asyncFnце звичайна функція у перекладеному коді, це екземпляр Functionчи GeneratorFunctionні AsyncFunction. Щоб переконатися, що це не дасть помилкових спрацьовувань для генератора та звичайних функцій у перекладеному коді:
const AsyncFunction = (async () => {}).constructor;
const GeneratorFunction = (function* () => {}).constructor;
(asyncFn instanceof AsyncFunction && AsyncFunction !== Function && AsyncFunction !== GeneratorFunction) === true
Оскільки власні asyncфункції були офіційно представлені в Node.js в 2017 році, питання, ймовірно, стосується реалізації asyncфункції Babel , яка покладається на transform-async-to-generatorтранпіляцію asyncдо функцій генератора, а також може використовуватись transform-regeneratorдля транпіляції генератора до звичайних функцій.
Результатом asyncвиклику функції є обіцянка. Відповідно до пропозиції , обіцянка чи не обіцянка може бути передана await, тому await callback()є універсальною.
Є лише кілька випадків, коли це може знадобитися. Наприклад, власні asyncфункції використовують власні обіцянки внутрішньо і не піднімають глобальні, Promiseякщо їх реалізація була змінена:
let NativePromise = Promise;
Promise = CustomPromiseImplementation;
Promise.resolve() instanceof Promise === true
(async () => {})() instanceof Promise === false;
(async () => {})() instanceof NativePromise === true;
Це може вплинути на поведінку функції (це відома проблема реалізації обіцянок Angular та Zone.js ). Навіть тоді переважно виявити, що значення функції, що повертається, не є очікуваним, Promiseзамість того, щоб виявити, що функцією є async, оскільки ця сама проблема застосовна до будь-якої функції, яка використовує альтернативну реалізацію обіцянки, а не тільки async( рішення вказаної проблеми Angular полягає в обгортанні asyncreturn значення з Promise.resolve).
Практика
Зовні asyncфункція - це просто функція, яка безумовно повертає рідну обіцянку, тому до неї слід ставитись як до такої. Навіть якщо функція колись була визначенаasync , вона в якийсь момент може бути перетворена і стати регулярною функцією.
Функція, яка може повернути обіцянку
У ES6 функція, яка потенційно повертає обіцянку, може використовуватися з Promise.resolve(допускає синхронні помилки) або обгорнутим Promiseконструктором (обробляє синхронні помилки):
Promise.resolve(fnThatPossiblyReturnsAPromise())
.then(result => ...);
new Promise(resolve => resolve(fnThatPossiblyReturnsAPromiseOrThrows()))
.then(result => ...);
У ES2017 це зроблено за допомогою await(так слід писати приклад із запитання):
let result = await fnThatPossiblyReturnsAPromiseOrThrows();
...
Функція, яка повинна повертати обіцянку
Перевірка того, чи є об’єкт обіцянкою, - це питання окремого питання , але, як правило, воно не повинно бути занадто суворим або вільним, щоб охопити кутові справи. instanceof Promiseможе не працювати, якщо глобальний Promiseбув замінений, Promise !== (async () => {})().constructor . Це може статися, коли Angular та non-Angular програми взаємодіють.
asyncСпершу потрібно викликати функцію, яка вимагає бути , тобто завжди повертати обіцянку, потім повертається значення перевіряється як обіцянку:
let promise = fnThatShouldReturnAPromise();
if (promise && typeof promise.then === 'function' && promise[Symbol.toStringTag] === 'Promise') {
} else {
throw new Error('async function expected');
}
TL; DR: asyncфункції не слід відрізняти від звичайних функцій, які повертають обіцянки. Не існує надійного способу та немає практичних причин для виявлення неприродних перекладених asyncфункцій.
awaitне обіцяєте, це все одно автоматично оберне)