Примечание редактора. Я не разработчик языков и не создаю компиляторы. Я хотел бы получить отзывы других о том, почему эта идея сработает/не сработает, в разделе комментариев.

Промисы — это чистая гениальность, и они стали значительным дополнением к языку JavaScript в ES2015, построенном на плечах гигантов. Теперь я убежден, что это все, что нужно разработчикам для обработки любой асинхронной ситуации в своем коде. (Двигайтесь дальше, RxJS.)

Но для меня также очевидно, что он был добавлен позже, с учетом обратной совместимости. Это здорово, но также заставляет задуматься… а что, если бы вместо этого JavaScript был асинхронным по умолчанию? Я называю эту идею JavaScript++.

Позвольте мне поддержать базовую концепцию Promise/Await, которая может быть новой для вас — то, что я называю «автоматической упаковкой»:

let a;
a = 5; // 5
a = Promise.resolve(5); // a is a Promise(5)
a = await Promise.resolve(5); // 5
a = await 5; // auto-boxed as a Promise(5), then unwrapped by await

Все эти операторы функционально эквивалентны, даже последний; это правда! Давайте еще немного расширим эту концепцию, взглянув на функции:

let syncFunc = () => 5; // returns 5
let asyncFunc = async () => 5; // returns a Promise(5)
let a;
a = syncFunc(); // 5
a = asyncFunc(); // a is a Promise(5)
a = await asyncFunc(); // 5
a = await syncFunc(); // auto-boxed as a Promise(5), then unwrapped

Разве это не круто? Это означает, что «асинхронность» обратно совместима — вам не нужно использовать ее в промисе! Напрашивается вопрос… что, если бы язык мог автоматически упаковывать/распаковывать везде по умолчанию? Давайте немного изменим наш синтаксис на псевдокод, где «::» означает предпочтение авто-бокса Promise:

let syncFunc = () => 5;
let asyncFunc = () ::=> 5; // returns a Promise(5)
let a;
a = 5;
a = Promise.resolve(5); // a is a Promise(5)
a =:: Promise.resolve(5);
a =:: 5;
a = syncFunc();
a = asyncFunc(); // a is a Promise(5)
a =:: asyncFunc();
a =:: syncFunc(); // auto-boxed as a Promise(5), then unwrapped

Причина, по которой мы должны различать «=» и «=::», заключается в том, что иногда мы хотим, чтобы асинхронная работа (например, вызов API) выполнялась «в фоновом режиме», в то время как другая работа выполняется немедленно; мы не хотим блокировать/ожидать немедленно. (Это похоже на концепции многопоточности, когда фоновый поток не «присоединяется»/ожидается до тех пор, пока в этом нет крайней необходимости.)

Но нужно ли вообще различать функции «() =›» и «() ::=›»? Почему бы не всегда возвращать Promise и позволить вызывающей стороне решать, ждать ли «::» или нет?

let func = () => 5; // auto-boxed as a Promise
let func = () ::=> 5; // which syntax do you prefer?
let a;
a =:: func();
a = func(); // a is a Promise(5)

Еще одно преимущество ВСЕХ функций, возвращающих обещание, заключается в том, что вам никогда не придется решать, является ли функция «асинхронной» или нет. Это часто является причиной рефакторинга, когда вдруг функция зависит от другой асинхронной функции; он должен либо сам стать асинхронным, либо неуклюже использовать API «.then(…)» Promise. Эта проблема исчезнет, ​​если КАЖДАЯ функция будет асинхронной!

Наконец, чтобы действительно сделать асинхронные/промисы по умолчанию (потому что мы предполагаем, что большинство промисов ожидаются немедленно?), мы просто заменяем синтаксис «::», чтобы он означал «не НЕ ждать»:

let func = () => 5; // auto-boxed as a Promise(5)
let a;
a = func(); // Promise(5) is unwrapped as a 5
a =:: func(); // a is a Promise(5)
// ... do more work ...
a = a // Promise(5) is unwrapped as a 5
a = a // 5 is auto-boxed into a Promise(5), then unwrapped as a 5

Конечно, необходимо также учитывать и других операторов, например:

let func = () => 5; // auto-boxed as a Promise (5)
let a;
a = func() + func() // plus unwraps all Promises
a = func() + 5 // OK
a = func() +:: func() // invalid - cannot add a Promise
a = 5 +:: func() // invalid - cannot add a Promise
a = func() +:: 5 // invalid - cannot add a Promise

Я оставлю это здесь в качестве упражнения для читателя. 🤔

По общему признанию, этот JavaScript++ определенно нарушил бы обратную совместимость, и поэтому, вероятно, это скорее умственное упражнение, чем что-либо еще. Но… возможно, это вдохновило кого-то более умного, чем я, на следующий большой скачок в асинхронной обработке JavaScript. Кто знает?

«Асинхронный по умолчанию» — сработает ли это? Дайте мне знать, что вы думаете в комментариях ниже.