Async: `async`-Funktionsunterstützung

Erstellt am 16. März 2017  ·  10Kommentare  ·  Quelle: caolan/async

Einer der Elefanten im Raum ist die neue Unterstützung für async / await , die für Node und Chrome verfügbar ist und bald alle anderen großen Browser treffen wird. Ich habe darüber nachgedacht, was Async in der Welt async / await bewirken kann.

Derzeit können wir async Funktionen anpassen, indem wir sie mit asyncify . Da eine async -Funktion im Wesentlichen nur eine Funktion ist, die ein Promise zurückgibt, kann dieser alte Adapter sie leicht in eine Callback-Funktion umwandeln. Es führt jedoch zu einem etwas absurden Aussehen:

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

Eines der Merkmale in der Spezifikation für async -Funktionen ist jedoch Folgendes:

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

Auf diese Weise können (native) async -Funktionen leicht erkannt werden. Wir könnten diese Technik verwenden, um sie automatisch asyncify zu machen. Das obige Beispiel wird zu:

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

...was viel natürlicher zu fließen scheint. Ich denke auch, dass wir weiterhin Rückrufe verwenden sollten. Wenn ein Benutzer das Ergebnis await sehen wollte, müsste er die Funktion promisify oder pify Async als Ganzes:

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

Die obige Methode zum Erkennen async -Funktionen funktioniert nur mit nativen Funktionen. Ich glaube nicht, dass es eine Möglichkeit gibt, transpilierte Babel-Funktionen zu erkennen. Wir können sicherlich keine normalen Funktionen erkennen, die einfach Promises zurückgeben, da wir dann rückwirkend keinen Callback weitergeben müssten. Es gibt eine große Einschränkung, dass dies nur in sehr modernen Umgebungen ohne Transpiler funktionieren würde, da Sie sonst immer noch manuell mit asyncify müssen.

Außerdem machen zugegebenermaßen viele Async-Methoden mit async / await keinen Sinn. Die meisten Kontrollflussmethoden (mit Ausnahme von Dingen wie auto und queue ) lassen sich einfacher mit nativen Kontrollflusskonstrukten replizieren. map und parallel können durch Promise.map und Promise.all ersetzt werden. Allerdings wären die einschränkenden Sammelfunktionen sehr nützlich, ebenso wie auto und einige andere. (Außerdem ist autoInject mit async Funktionen ein asynchroner Kontrollflusstraum!)

enhancement feedback-wanted

Hilfreichster Kommentar

Gibt es einen Grund, Object.getPrototypeOf(asyncFn)[Symbol.toStringTag] === "AsyncFunction" zu machen, oder können wir asyncFn[Symbol.toStringTag] === "AsyncFunction" machen (scheint in FF zu funktionieren)?

Das ist nur die kanonische ECMA-Spezifikation. Ich denke, theoretisch könnte jemand asyncFn[Symbol.toStringTag] überschreiben.

So ist der Vorschlag, jedes Mal, wenn jemand einen Rückruf im Format cb(err, arg) bereitstellt, sollten wir erkennen, ob es sich um eine AsyncFunction handelt; Wenn es sich um eine asynchrone Funktion handelt, sollten wir Promisify anwenden, andernfalls verwenden Sie sie unverändert

Ich glaube, du hast es ein bisschen hinterher. Überall dort, wo wir eine Callback-akzeptierende iterierte Funktion ( function(args..., callback) {} ) akzeptieren, sollten wir prüfen, ob es sich um eine async -Funktion handelt, und dann asyncify .

Das await Beispiel ist das, was jemand tun würde, wenn er eine Async-Methode await verwenden wollte. Ich denke nicht, dass Async-Methoden anfangen sollten, Versprechen zurückzugeben, damit das funktioniert - überlassen Sie es dem Benutzer, dies zu tun.

Alle 10 Kommentare

Ich werde noch etwas darüber nachdenken, aber ich möchte ein paar technische Fragen stellen, nur damit ich versuchen kann, mir besser vorzustellen, wie das aussieht.

Gibt es einen Grund, Object.getPrototypeOf(asyncFn)[Symbol.toStringTag] === "AsyncFunction" zu machen, oder können wir asyncFn[Symbol.toStringTag] === "AsyncFunction" machen (scheint in FF zu funktionieren)?

So ist der Vorschlag, jedes Mal, wenn jemand einen Rückruf im Format cb(err, arg) bereitstellt, sollten wir erkennen, ob es sich um ein AsyncFunction handelt; Wenn es sich um eine asynchrone Funktion handelt, sollten wir promisify anwenden, andernfalls verwenden Sie sie unverändert

Entschuldigung, ich folge dem await-Beispiel nicht, wenn wir feststellen, dass die Funktion ein AsyncFunction ist, was sind die Herausforderungen bei der Unterstützung von await ?

Gibt es einen Grund, Object.getPrototypeOf(asyncFn)[Symbol.toStringTag] === "AsyncFunction" zu machen, oder können wir asyncFn[Symbol.toStringTag] === "AsyncFunction" machen (scheint in FF zu funktionieren)?

Das ist nur die kanonische ECMA-Spezifikation. Ich denke, theoretisch könnte jemand asyncFn[Symbol.toStringTag] überschreiben.

So ist der Vorschlag, jedes Mal, wenn jemand einen Rückruf im Format cb(err, arg) bereitstellt, sollten wir erkennen, ob es sich um eine AsyncFunction handelt; Wenn es sich um eine asynchrone Funktion handelt, sollten wir Promisify anwenden, andernfalls verwenden Sie sie unverändert

Ich glaube, du hast es ein bisschen hinterher. Überall dort, wo wir eine Callback-akzeptierende iterierte Funktion ( function(args..., callback) {} ) akzeptieren, sollten wir prüfen, ob es sich um eine async -Funktion handelt, und dann asyncify .

Das await Beispiel ist das, was jemand tun würde, wenn er eine Async-Methode await verwenden wollte. Ich denke nicht, dass Async-Methoden anfangen sollten, Versprechen zurückzugeben, damit das funktioniert - überlassen Sie es dem Benutzer, dies zu tun.

Implementiert in #1390 !

Dies war eine Breaking Change und hat unseren bereitgestellten Code beschädigt. Bitte überlegen Sie es sich zweimal, wenn Sie solche Dinge tun, ohne die Hauptversion zu erhöhen.

PS: Danke für all die großartige Arbeit, die Sie mit dieser Bibliothek leisten 😄

Schießen! Was ist kaputt gegangen. Könnten Sie bitte ein Ticket mit Details erstellen
Umgebung, in der das nicht funktioniert hat?
Danke!

Am Mittwoch, 5. April 2017 um 10:18 Uhr Manuel Valls Fernández <
[email protected]> schrieb:

Dies war eine Breaking Change und hat unseren bereitgestellten Code beschädigt. Bitte überlegen Sie es sich zweimal
wenn Sie solche Dinge tun, ohne die Hauptversion zu erhöhen.

PS: Danke für all die großartige Arbeit, die Sie mit dieser Bibliothek leisten 😄


Sie erhalten dies, weil Sie kommentiert haben.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/caolan/async/issues/1386#issuecomment-291875817 oder stumm
der Faden
https://github.com/notifications/unsubscribe-auth/ADUIEPNkTSOVuuiwucBVrH983X6B568Wks5rs6K3gaJpZM4Mf64R
.

Einverstanden, es hat auch meinen Build kaputt gemacht ...

Ein Wasserfall, der eine asynchrone Funktion aufrief, die vor ein paar Tagen funktionierte, begann mit einem „cb is not function“ fehlzuschlagen, da der asynchrone Rückruf nicht mehr für die Funktion bereitgestellt wurde.

Es tut uns leid, dass wir Ihren Code geknackt haben. Wir haben Ihren Anwendungsfall für async -Funktionen nicht vorausgesehen. Ich würde empfehlen, auf 2.2.0 zurückzusetzen oder Ihren Code auf return die benötigten Werte umzugestalten, anstatt Rückrufe zu verwenden. Leider ist die Katze mit dieser Funktion aus dem Sack, sodass wir nicht zurücksetzen können.

@aearly Bitte nicht erwähnen!! Es ist wirklich nett von dir zu antworten :1st_place_medal:

@manvalls hat mir eine großartige Lösung angedeutet, für die kein Rollback erforderlich war. Als Sie das Symbol verwenden, um das async in der Funktionsdeklaration zu erkennen, hat er sich einen cleveren Weg ausgedacht, um die Erkennung zu überlisten.

Mein Wasserfall verwendete Funktionen, die aus anderen Modulen exportiert wurden, eines davon war ein async -Modul und verursachte somit den Fehler.

Also einfach durch Wechseln von:

... 
/* 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 => {
...
}

Zu:

... 
/* 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 => {
...
}

Danke dir nochmal

können wir async/await mit async.autoInject() verwenden?

async.autoInject({

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

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

Scheint nicht zu funktionieren, ich bekomme:

Fehler: AutoInject-Aufgabenfunktionen erfordern explizite Parameter.
unter /Users/alexamil/WebstormProjects/nabisco/cdt-now/node_modules/async/dist/async.js:2081:23
unter /Users/alexamil/WebstormProjects/nabisco/cdt-now/node_modules/async

@ORESoftware ja, async Funktionen sollten mit autoInject $ funktionieren. Ich habe den von Ihnen geposteten Code in Chrome getestet und er lief. Ich habe im letzten Rückruf ein ReferenceError erhalten, da conn1 und conn2 undefined sind. Nach der Umstellung auf

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

es funktioniert gut. Wir unterstützen jedoch keine transpilierten async -Funktionen. Transpilieren Sie Ihren Code?

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen