Примечание редактора. Я не разработчик языков и не создаю компиляторы. Я хотел бы получить отзывы других о том, почему эта идея сработает/не сработает, в разделе комментариев.
Промисы — это чистая гениальность, и они стали значительным дополнением к языку 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. Кто знает?
«Асинхронный по умолчанию» — сработает ли это? Дайте мне знать, что вы думаете в комментариях ниже.