Async: Поддержка `асинхронной` функции

Созданный на 16 мар. 2017  ·  10Комментарии  ·  Источник: caolan/async

Одним из слонов в этой комнате является новая поддержка async / await , которая появилась в Node и Chrome и скоро появится во всех основных браузерах. Я думал о том, что Async может сделать в мире async / await .

В настоящее время мы можем адаптировать функции async , оборачивая их в asyncify . Поскольку функция async — это, по сути, просто функция, возвращающая Promise, этот старый адаптер может легко преобразовать ее в функцию обратного вызова. Однако это приводит к несколько абсурдному виду:

async.mapLimit(arr, 10, async.asyncify(async (val) => {
  let foo = await doSomething(val);
  //...
 return bar;
}), done);

Однако одна из особенностей спецификации функций async заключается в следующем:

Object.getPrototypeOf(asyncFn)[Symbol.toStringTag] === "AsyncFunction"

Это дает возможность легко обнаруживать (собственные) функции async . Мы могли бы использовать эту технику, чтобы автоматически asyncify их. Приведенный выше пример становится:

async.mapLimit(arr, 10, async (val) => {
  let foo = await doSomething(val);
  //...
 return bar;
}, done);

...что кажется более естественным. Я также думаю, что мы должны продолжать использовать обратные вызовы. Если бы пользователь хотел await результата, ему пришлось бы promisify функции или pify Async в целом:

let result = await pify(async.mapLimit)(arr, 10, async (val) => {
  let foo = await doSomething(val);
  //...
 return bar;
});

Приведенный выше метод обнаружения функций async работает только с собственными функциями. Я не думаю, что есть способ обнаружить транспилированные функции Babel. Мы, конечно, не можем обнаружить нормальные функции, которые просто возвращают промисы, потому что нам пришлось бы задним числом не передавать обратный вызов. Было бы огромное предостережение, что это будет работать только без транспилятора в очень современных средах, иначе вам все равно придется вручную обертывать asyncify .

Также следует признать, что многие асинхронные методы не имеют смысла с async / await . Большинство методов потока управления (за исключением таких вещей, как auto и queue ) легче воспроизвести с помощью собственных конструкций потока управления. map и parallel можно заменить на Promise.map и Promise.all . Тем не менее, функции ограничения коллекции были бы очень полезны, а также auto и некоторые другие. (Кроме того, autoInject с функциями async — мечта об асинхронном потоке управления!)

enhancement feedback-wanted

Самый полезный комментарий

Есть ли причина делать Object.getPrototypeOf(asyncFn)[Symbol.toStringTag] === "AsyncFunction" или мы можем сделать asyncFn[Symbol.toStringTag] === "AsyncFunction" (кажется, работает в FF)?

Это просто канонический способ спецификации ECMA. Я предполагаю, что теоретически кто-то может перезаписать asyncFn[Symbol.toStringTag] .

То же самое и с предложением: каждый раз, когда кто-то предоставляет обратный вызов формата cb(err, arg), мы должны определить, является ли это AsyncFunction; если это асинхронная функция, мы должны применить обещание, в противном случае используйте ее как есть

Я думаю, что у вас есть это немного назад. Везде, где мы принимаем итерируемую функцию, принимающую обратный вызов ( function(args..., callback) {} ), мы должны проверить, является ли она функцией async , а затем asyncify ее.

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

Все 10 Комментарий

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

Есть ли причина делать Object.getPrototypeOf(asyncFn)[Symbol.toStringTag] === "AsyncFunction" или мы можем сделать asyncFn[Symbol.toStringTag] === "AsyncFunction" (кажется, работает в FF)?

То же самое и с предложением: каждый раз, когда кто-то предоставляет обратный вызов формата cb(err, arg) , мы должны определить, является ли он AsyncFunction ; если это асинхронная функция, мы должны применить promisify , в противном случае использовать ее как есть

Также извините, я не следую примеру ожидания, если мы обнаружим, что функция является AsyncFunction , каковы проблемы с поддержкой await ?

Есть ли причина делать Object.getPrototypeOf(asyncFn)[Symbol.toStringTag] === "AsyncFunction" или мы можем сделать asyncFn[Symbol.toStringTag] === "AsyncFunction" (кажется, работает в FF)?

Это просто канонический способ спецификации ECMA. Я предполагаю, что теоретически кто-то может перезаписать asyncFn[Symbol.toStringTag] .

То же самое и с предложением: каждый раз, когда кто-то предоставляет обратный вызов формата cb(err, arg), мы должны определить, является ли это AsyncFunction; если это асинхронная функция, мы должны применить обещание, в противном случае используйте ее как есть

Я думаю, что у вас есть это немного назад. Везде, где мы принимаем итерируемую функцию, принимающую обратный вызов ( function(args..., callback) {} ), мы должны проверить, является ли она функцией async , а затем asyncify ее.

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

Реализовано в #1390!

Это было критическое изменение, и оно сломало наш развернутый код. Пожалуйста, подумайте дважды, когда делаете такие вещи, не увеличивая основную версию.

PS: спасибо за всю отличную работу, которую вы проделали с этой библиотекой 😄

Стрелять! Что сломалось. Не могли бы вы создать тикет с подробной информацией о
среда, в которой это не сработало?
Спасибо!

В среду, 5 апреля 2017 г., в 10:18 Мануэль Вальс Фернандес <
уведомления@github.com> написал:

Это было критическое изменение, и оно сломало наш развернутый код. Пожалуйста, подумайте дважды
при выполнении таких вещей без увеличения основной версии.

PS: спасибо за всю отличную работу, которую вы проделали с этой библиотекой 😄


Вы получаете это, потому что вы прокомментировали.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/caolan/async/issues/1386#issuecomment-291875817 или отключить звук
нить
https://github.com/notifications/unsubscribe-auth/ADUIEPNkTSOVuuiwucBVrH983X6B568Wks5rs6K3gaJpZM4Mf64R
.

Согласен, это тоже сломало мою сборку...

Водопад, который вызывал асинхронную функцию, которая работала несколько дней назад, начал давать сбой с сообщением «cb is not function», потому что асинхронный обратный вызов больше не предоставлялся функции.

Извините, мы сломали ваш код. Мы не ожидали вашего варианта использования функций async . Я бы порекомендовал откатиться до 2.2.0 или реорганизовать ваш код до return нужных вам значений, а не использовать обратные вызовы. К сожалению, с этой фичей не все в порядке, поэтому мы не можем откатиться.

@aearly Пожалуйста, не упоминайте об этом!! Очень мило, что вы ответили :1st_place_medal:

@manvalls подсказал мне отличное решение, которое не требует отката. Поскольку вы используете символ для обнаружения async в объявлении функции, он придумал хитрый способ обмануть обнаружение.

В моем водопаде использовались функции, экспортированные из других модулей, один из них был async и, таким образом, вызывал сбой.

Итак, просто изменив:

... 
/* services module */
function doThis(param, cb) {
...
}

async function doThatAsync(param, cb) {
...
}

module.exports = {
  doThis: doThis,
  doThat: doThatAsync  
}; 

...
async.waterfall([
  services.doThis,
  services.doThat,  // fails with "cb is not a function"
], err => {
...
}

К:

... 
/* services module */
function doThis(param, cb) {
...
}

async function doThatAsync(param, cb) {
...
}

module.exports = {
  doThis: doThis,
  doThat: (...args) => doThatAsync(..args)   // cheating the detection
}; 

...
async.waterfall([
  services.doThis,
  services.doThat, /* it works!!! */
], err => {
...
}

Большое спасибо еще раз

можем ли мы использовать async/await с async.autoInject()?

async.autoInject({

    conn1: async function () {
      return conn1;
    },

    conn2: async function () {
      return conn2;
    },
});

не работает, я получаю:

Ошибка: функции задачи autoInject требуют явных параметров.
в /Users/alexamil/WebstormProjects/nabisco/cdt-now/node_modules/async/dist/async.js:2081:23
в /Users/alexamil/WebstormProjects/nabisco/cdt-now/node_modules/async

@ORESoftware да, функции async должны работать с autoInject . Я протестировал код, который вы разместили в Chrome, и он заработал. Я получил ReferenceError в финальном обратном вызове, поскольку conn1 и conn2 равны undefined . После изменения его на

async.autoInject({
    conn1: async function () {
      return 'foo'
    },
    conn2: async function () {
      return 'bar'
    },
})

это работает нормально. Однако мы не поддерживаем транспилированные функции async . Вы транспилируете свой код?

Была ли эта страница полезной?
0 / 5 - 0 рейтинги