Experimental support for 'Top-Level Await' just landed in Node.js core and Chrome Dev Tools, and Safari Web Inspector!

Да да, в Node.js 14.3 уже есть возможность писать верхнеуровневые await , пока, правда, в экспериментальном режиме. А так же еще одна особенность: они доступны только в ESM модулях иначе не сработают. Если вы пользуетесь Babel, то вы можете уже использовать в продакшене эту фичу. Так же top level await были добавлены в TypeScript 3.8 еще в Феврале 2020 года. Так же эта возможность давно доступна в проекте Deno.

Помимо Node.js эта фича языка доступан в Chrome Dev Tools и Safari Web Inspector.

let data = (await fetch('https://geekjob.ru/vacancies?format=json')).data;

console.log(data);

Но все же, если хочется использовать эту фичу в ноде нативно без транспайлеров, то вам нужно будет запуститься с флагами. Без флагов получится такой вариант - old way.

// index.msj

await Promise.resolve(console.log('🎉'));
// → SyntaxError: await is only valid in async function


void async function() {
    await Promise.resolve(console.log('🎉'));
    // → 🎉
}();

И если вы запустите проект с включенными опциями, то результат будет ок в обоих случаях.

node --experimental-top-level-await --harmony-top-level-await index.mjs

В чем собственно суть проблемы?

В JS много асинхронного кода, особенно если мы работаем с библиотеками баз данных. Node.js это не только среда для серверных веб-приложений, но так же можно писать разные вспомогательные скрипты, где асинхронность избыточна.

Типичный кейс работы с базой данных в Express:

async routeFunction(req, res, next) {

   let db = await dbConnect();
   let result = await db.query('...');

   if (result.some) {
     ...
   }
   else {
     ...
   }

   next();
}

Если же этот участок переписывать через промисы или еще хуже через колбэки, то код станет менее читаемым и более сложным.

С новым подходом в данном случае просто уйдет слово async и функции можно будет делать более универсальными.

Второй кейс - это необходимая синхронность, когда происходит подключение разных библиотек, но эта фича будет полезна в браузерах, когда туда завезут top level await'ы. Например:

var jQuery;
try {
  jQuery = await import('https://ajax.googleapis.com/libs/jquery.js');
} catch {
  jQuery = await import('/local/jquery.js');
}

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

<script src="//ajax.googleapis.com/libs/jquery/jquery.js"></script>
<script>window.jQuery || document.write('<script src="/local/jquery.js">\x3C/script>')</script>

Если интересна тема, больше подробностей на странице предложения:

tc39/proposal-top-level-await
top-level `await` proposal for ECMAScript (stage 3) - tc39/proposal-top-level-await