webentwicklung-frage-antwort-db.com.de

async Methodenaufrufe verketten - Javascript

Sie haben ein Prototypobjekt Foo mit zwei asynchronen Methodenaufrufen, bar und baz.

var bob = new Foo()

Foo.prototype.bar = function land(callback) {
  setTimeout(function() {
    callback()
    console.log('bar');
  }, 3000);
};

Foo.prototype.baz = function land(callback) {
  setTimeout(function() {
    callback()
    console.log('baz');
  }, 3000);
};

Wir wollen bob.bar (). Baz () machen und "log" und "baz" nacheinander protokollieren.

Wenn Sie die Methodenaufrufe nicht ändern können (einschließlich der Weitergabe Ihrer Rückruffunktion), wie können Sie einen Standardrückruf an diese Methodenaufrufe übergeben? 

Einige Ideen:

  1. Wrap "bob" mit Dekorateur (noch unklar in der Implementierung, könnte ein kleines Beispiel verwenden)

  2. Konstruktor ändern, um einen Standard-Rückruf zuzuweisen, falls noch kein zugewiesen wurde (nicht berücksichtigt, ob dies möglich ist oder nicht)

  3. Verwenden Sie einen Generator-Wrapper, der die nächste Methode so lange aufruft, bis keine mehr vorhanden ist.

13
Anthony Chung

Der empfohlene Weg ist stattdessen die Verwendung von Versprechen . Da dies ein gemeinschaftsweiter Trend ist, asynchrone Dinge zu tun.

Wir wollen bob.bar (). Baz () machen und "log" und "baz" .__ protokollieren lassen. der Reihe nach.

Warum möchten Sie das nur tun, um diese bob.bar().baz() "Syntax" zu erreichen? Wenn Sie dies ganz einfach tun können, verwenden Sie die Promise-API ohne zusätzlichen Aufwand, um diese Syntax zu aktivieren, die die Codekomplexität tatsächlich erhöht, wodurch der eigentliche Code schwer verständlich wird.

Daher sollten Sie den versprechenbasierten Ansatz in etwa wie folgt in Betracht ziehen, der viel mehr Flexibilität bietet, als Sie mit Ihrem Ansatz erreicht hätten:

Foo.prototype.bar = function () {
    return new Promise(function (resolve) {
        setTimeout(function () {
            resolve()
            console.log('bar');
        }, 3000);
    };
};

Foo.prototype.baz = function () {
    return new Promise(function (resolve) {
        setTimeout(function () {
            resolve()
            console.log('baz');
        }, 3000);
    };
};

Jetzt würden Sie dies tun, um sie sequentiell nacheinander auszuführen:

var bob = new Foo();

bob.bar().then(function() {
   return bob.baz();
});

// If you're using ES2015+ you could even do:
bob.bar().then(() => bob.baz());

Wenn Sie mehr Funktionen verketten möchten, können Sie dies einfach tun:

bob.bar()
    .then(() => bob.baz())
    .then(() => bob.anotherBaz())
    .then(() => bob.somethingElse());  

Wenn Sie es nicht gewohnt sind, Versprechungen zu verwenden, möchten Sie vielleicht lesen Sie diese

9
kabirbaidhya

Warnung das ist noch nicht ganz richtig. Idealerweise würden wir die Promise-Unterklasse untergliedern und über eine korrekte Dann/Catch-Funktionalität verfügen, es gibt jedoch einige Einschränkungen bei der Unterklasse bluebird Promise . Die Idee ist, ein internes Array von Versprechungserzeugungsfunktionen zu speichern. Wenn ein Versprechen darauf wartet (dann warten/warten), warten Sie auf diese Versprechen.

const Promise = require('bluebird');

class Foo {
  constructor() {
    this.queue = [];
  }

  // promise generating function simply returns called pGen
  pFunc(i,pGen) {
    return pGen();
  }

  bar() {
    const _bar = () => {
      return new Promise( (resolve,reject) => {
        setTimeout( () => {
          console.log('bar',Date.now());
          resolve();
        },Math.random()*1000);
      })      
    }
    this.queue.Push(_bar);
    return this;
  }

  baz() {
    const _baz = () => {
      return new Promise( (resolve,reject) => {
        setTimeout( () => {
          console.log('baz',Date.now());
          resolve();
        },Math.random()*1000);
      })      
    }
    this.queue.Push(_baz);
    return this;
  }

  then(func) {
    return Promise.reduce(this.queue, this.pFunc, 0).then(func);
  }
}


const foo = new Foo();
foo.bar().baz().then( () => {
  console.log('done')
})

ergebnis:

[email protected]:~/Desktop/Dropbox/code/js/async-chain$ node index.js 
bar 1492082650917
baz 1492082651511
done
3
Mark Essel

Wenn Sie Callback-Hölle vermeiden und Ihren Verstand halten möchten, sind ES6-Versprechen die am besten geeignete Lösung für eine funktionale Programmierung. Sie ketten Ihre sequentiellen asynchronen Aufgaben in der asynchronen Zeitleiste genauso zusammen, wie Sie in einer synchronen Zeitleiste arbeiten.

In diesem speziellen Fall müssen Sie nur Ihre asynchronen Funktionen versprechen. Angenommen, Ihre asynchronen Funktionen benötigen Daten und einen Rückruf wie asynch(data,myCallback). Nehmen wir an, der Rückruf ist fehlerhafter Typ.

Sowie;

var myCallback = (error,result) => error ? doErrorAction(error)
                                         : doNormalAction(result)

Wenn Ihre asynchrone Funktion versprochen wird, erhalten Sie tatsächlich eine Funktion, die Ihre Daten übernimmt und ein Versprechen zurückgibt. Es wird erwartet, dass Sie myCallback in der Phase then anwenden. Der Rückgabewert von myCallback wird dann an die nächste Stufe übergeben, in der Sie eine weitere asynch-Funktion aufrufen können, die mit dem Rückgabewert von myCallback geliefert wird. Dies wird so lange fortgesetzt, wie Sie es benötigen. Mal sehen, wie wir diese Zusammenfassung in Ihren Workflow implementieren werden.

function Foo(){}

function promisify(fun){
  return (data) => new Promise((resolve,reject) => fun(data, (err,res) => err ? reject(err) : resolve(res)));
}

function myCallback(val) {
  console.log("hey..! i've got this:",val);
  return val;
}

var bob = new Foo();

Foo.prototype.bar = function land(value, callback) {
  setTimeout(function() {
    callback(false,value*2);  // no error returned but value doubled and supplied to callback
    console.log('bar');
  }, 1000);
};

Foo.prototype.baz = function land(value, callback) {
  setTimeout(function() {
    callback(false,value*2);  // no error returned but value doubled and supplied to callback
    console.log('baz');
  }, 1000);
};

Foo.prototype.bar = promisify(Foo.prototype.bar);
Foo.prototype.baz = promisify(Foo.prototype.baz);

bob.bar(1)
   .then(myCallback)
   .then(bob.baz)
   .then(myCallback)

0
Redu