2015-09-28 16 views
21

In meinem NodeJS ausführen ich brauche 2 oder 3 API-Aufrufe zu machen, und jeder wird einige Daten zurück. Nachdem alle API-Aufrufe abgeschlossen sind, möchte ich alle Daten in einem einzigen JSON-Objekt sammeln, um sie an das Frontend zu senden.Wie mehrere Asynchron-Funktionen dann ausführen Rückruf Code

Ich weiß, wie dies die API-Rückrufe mit tun (der nächste Anruf in der vorherigen Aufruf der Rückruf passieren wird), aber dies wäre langsam:

//1st request 
request('http://www.example.com', function (err1, res1, body) { 

    //2nd request 
    request('http://www.example2.com', function (err2, res2, body2) { 

    //combine data and do something with it 

    }); 

}); 

Ich weiß, dass Sie auch etwas ähnliches und sauberere tun könnte mit Versprechungen, aber ich denke, dass das gleiche Konzept gilt, wo der nächste Anruf nicht ausgeführt wird, bis der aktuelle beendet ist.

Gibt es eine Möglichkeit alle Funktionen zur gleichen Zeit zu nennen, aber für meinen letzten Code-Block zu warten, für alle API vor der Ausführung zu vervollständigen und liefern Daten rufen?

+0

Sie können auch mit 'bluebird' wenn Sie – corvid

+2

wollte; https://en.wikipedia.org/wiki/Immediately-invoked_function_expression

TL. Es gibt einfach keinen super sauberen Weg, es zu tun. Es ist trivial mit Versprechen aber. –

Antwort

40

Versprechen geben Sie Promise.all() (sowie Bibliothek diejenigen wie drossel ist das gilt für native Versprechen).

Also, was Sie tun können (nativ):

function requestAsync(url) { 
    return new Promise(function(resolve, reject) { 
     request(url, function(err, res, body) { 
      if (err) { return reject(err); } 
      return resolve([res, body]); 
     }); 
    }); 
} 
Promise.all([requestAsync('url1'), requestAsync('url2')]) 
    .then(function(allData) { 
     // All data available here in the order it was called. 
    }); 

Wenn Sie drossel haben, dies noch einfacher ist:

var requestAsync = promisify(request); 
var urls = ['url1', 'url2']; 
Promise.all(urls.map(requestAsync)).then(allData => { 
    // All data available here in the order of the elements in the array 
}); 
+0

Ich denke, wir können nicht versprechen Constructor Anti-Muster hier vermeiden. "( – thefourtheye

+1

@thefourtheye - es ist nicht ein Anti-Muster, wenn Sie eine Sache sind Einwickeln, die nicht ein Versprechen zurückkehrt Jemand hat das Versprechen macht keine andere Wahl. es sei denn, Sie eine Bibliotheksfunktion haben, die die promisifying Wrapper für Sie tut. – jfriend00

+1

@thefourtheye Sie leicht eine promisify Funktion ähnlich drossel der machen kann, die Hässlichkeit zu verstecken. –

10

Klingt wie async.parallel() tun würde, den Job auch wenn Sie möchten, dass async verwenden:

var async = require('async'); 

async.parallel({ 
    one: function(parallelCb) { 
     request('http://www.example1.com', function (err, res, body) { 
      parallelCb(null, {err: err, res: res, body: body}); 
     }); 
    }, 
    two: function(parallelCb) { 
     request('http://www.example2.com', function (err, res, body) { 
      parallelCb(null, {err: err, res: res, body: body}); 
     }); 
    }, 
    three: function(parallelCb) { 
     request('http://www.example3.com', function (err, res, body) { 
      parallelCb(null, {err: err, res: res, body: body}); 
     }); 
    } 
}, function(err, results) { 
    // results will have the results of all 3 
    console.log(results.one); 
    console.log(results.two); 
    console.log(results.three); 
}); 
+0

Danke Ben, Sie mein Wochenende super :-) –

+0

gemacht und nur eine Frage hier, können wir diese parallel Funktion ein, zwei und drei nach innen für Schleife nicht schreiben? –

+0

Ich bin mir nicht sicher, was Sie in der Schleife gemeint haben. Meine Vermutung ist das ganze async.parallel() innerhalb einer Schleife? Ich glaube, es sollte in Ordnung sein, wenn async.each() anstelle von nativen Schleifen verwendet wird. – Ben

0

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

Promise.all ist jetzt mit ES6 enthalten, damit Sie brauchen keine 3rd-Party-Bibliotheken überhaupt.

"Promise.all wartet für alle Erfüllungen (oder die erste Ablehnung)"

ich Setup habe ein Kern Promise.all() mit Refactoring itterations demonstrieren an: https://gist.github.com/rainabba/21bf3b741c6f9857d741b69ba8ad78b1

Ich verwende ein IIFE (unmittelbar involvierter Funktionsausdruck). Wenn Sie nicht vertraut sind, möchten Sie für das Beispiel unten sein, obwohl der Kern zeigt, wie mit einem IIFE. Dies ist eine Einschränkung der Callback-basierte asynchrone Funktionen DR

(function(promises){ 
    return new Promise((resolve, reject) => { 
     Promise.all(promises) 
      .then(values => { 
       console.log("resolved all promises") 
       console.dir(values); 
       resolve(values.reduce((sum,value) => { return sum+value })); //Use Array.prototype.reduce() to sum the values in the array 
      }) 
      .catch(err => { 
       console.dir(err); 
       throw err; 
      }); 

    }); 
})([ 
    new Promise((resolve, reject) => { 
     console.log("resolving 1"); 
     resolve(1); 
    }), 
    new Promise((resolve, reject) => { 
     console.log("resolving 2"); 
     resolve(2); 
    }) 
]).then(sum => { console.dir({ sum: sum }) }) 
Verwandte Themen