2017-01-20 1 views
0

Ich verwende Bluebird.map aber es mein Array von Objekten früh aus irgendeinem Grund zurückkehrt:Drossel Karte Rückkehr früh

function returnInvoicePrice(items) { 
    return Bluebird.map(items, function(item) { 
     db.collection('products').find({ 
      product_code : item.product_code 
     }).toArray(function(err, product) { 
      var invoice_price = product[0].invoice_price; 
      console.log('--product--'); 
      console.log(product); 
      return product; 
     }); 
    }).then(function(items) { 
     console.log('--items w/ invoice price--'); // this prints BEFORE my console.log(product) for some reason... 
     console.log(items); 
    }).catch(function(error) { 
     console.log('--bluebird error in returning price for each item--'); 
     console.log(error); 
    }); 
} 

returnInvoicePrice(items); 

Wer weiß, was könnte ich tun falsch sein?

Antwort

3

Ich sehe drei wichtigsten Dinge falsch hier:

  1. Drosseln .map() einen Rückruf benötigt, die ein Versprechen zurückgibt.
  2. Ihr .then() Griff, die console.log(items) tun muss return items so dass das Ergebnis Versprechen noch items als aufgelöst Wert.
  3. Wenn Sie returnInvoicePrice() anrufen, müssen Sie verwenden, um seinen Wert abzurufen. Diese Funktion gibt ein Versprechen zurück, das ein Meisterversprechen ist, das alle anderen Versprechen in .map() überwacht.

Die Funktion, die Sie Bluebird.map() passieren muss ein Versprechen zurückzukehren, die gelöst wird, wenn der Asynchron-Vorgang abgeschlossen ist. Wenn es nichts zurückgibt oder einen einfachen Wert zurückgibt, kann Bluebird nicht warten, bis die asynchrone Operation abgeschlossen ist und daher früher als gewünscht zurückkehren.

Wenn Ihre Version noch nicht Versprechungen unterstützen, gibt es Pakete gibt, wie mongodb-promise, die Sie Schnittstelle ein Versprechen zur verfügung, um zu MongoDB oder Sie können .promisify() oder .promisifyAll() Schnittstellen promisify in mongodb verwenden Bluebird.

Die neueste Version von mongodb für Node-Unterstützung verspricht in allen seinen asynchronen Schnittstellen, so dass Sie die Versprechen, die es bietet, direkt zurückgeben können.

Es scheint aus this doc for the latest mongodb dass xxx.find().toArray() ein Versprechen zurück, so dass Sie dieses Versprechen direkt aus dem .map() Rückruf wie diese zurückgeben kann (und auch die anderen Dinge beheben falsch):

function returnInvoicePrice(items) { 
    return Bluebird.map(items, function(item) { 
     // return promise here 
     return db.collection('products').find({ 
      product_code : item.product_code 
     }).toArray(function(err, product) { 
      var invoice_price = product[0].invoice_price; 
      console.log('--product--'); 
      console.log(product); 
      return product; 
     }); 
    }).then(function(items) { 
     console.log('--items w/ invoice price--'); // this prints BEFORE my console.log(product) for some reason... 
     console.log(items); 
     // also have to return items here 
     return items; 
    }).catch(function(error) { 
     console.log('--bluebird error in returning price for each item--'); 
     console.log(error); 
    }); 
} 

// have to use `.then()` on the returned promise here 
returnInvoicePrice(items).then(function(items) { 
    // can access items here 
}); 
+1

Added Codebeispiel und wies darauf hin, zwei andere Dinge falsch mit dem Code. – jfriend00

0

Wenn Sie diesen Code ausführen:

var Bluebird = require('bluebird'); 

function returnInvoicePrice(items) { 
    return Bluebird.map(items, function(item) { 
    console.log(item); 
    return item; 
    }).then(function(items) { 
    console.log('--items w/ invoice price--'); // this prints BEFORE my console.log(product) for some reason... 
    console.log(items); 
    }).catch(function(error) { 
    console.log('--bluebird error in returning price for each item--'); 
    console.log(error); 
    }); 
} 

returnInvoicePrice([1,2,3]); 

Sie werden die Bestellung sehen, die Sie erwarten. Der Unterschied ist, dass jfriend00 darauf hinweist, dass db.collection.find (...) asynchron ist und zu einem späteren Zeitpunkt ausgeführt wird. So müssen Sie diesen Teil in einem Versprechen wickeln:

return new Promise(function (resolve, reject) { 
    db.collection.find({ 
    : 
    resolve(); // this will signal Bluebird to execute the mapper function 
    }); 
} 

Auf diese Weise Drossel für die Antwort zu warten, wissen, bevor Sie fortfahren.

Sie können dies sehen durch diesen Code ausgeführt wird, die einen Asynchron-Prozess simuliert:

var Bluebird = require('bluebird'); 

function returnInvoicePrice(items) { 
    return Bluebird.map(items, function(item) { 
    return new Promise(function(resolve, reject) { 
     setTimeout(function() { 
     console.log(item); 
     resolve(item); 
     }, 500); 
    }); 
    }).then(function(items) { 
    console.log('--items w/ invoice price--'); // this prints BEFORE my console.log(product) for some reason... 
    console.log(items); 
    }).catch(function(error) { 
    console.log('--bluebird error in returning price for each item--'); 
    console.log(error); 
    }); 
} 

returnInvoicePrice([1,2,3]); 
+0

Warum etwas abstimmen, ohne einen Kommentar abzugeben ?? – rasmeister

+1

Ihr Versprechen Wrapper um 'db.collection.find()' geht davon aus, dass '.find()' ist synchron und einfach nicht funktionieren. Darüber hinaus gibt es mehrere andere und bessere Möglichkeiten, Versprechungen für die Verwendung mit mongodb zu bekommen. Die neueste Version enthält integrierte Versprechen, und wenn Sie diese Version aus irgendeinem Grund nicht verwenden, gibt es Module, die die gesamte Bibliothek promiifizieren.Und 'returnInvoicePrice()' gibt ein Versprechen zurück, so dass Sie '.then()' darauf verwenden müssen. Und der erste '.then() '- Handler muss' Items zurückgeben 'oder der aufgelöste Wert des Versprechens wird' undefiniert '. – jfriend00

+1

Sorry, ich wollte die resolve() innerhalb der enthaltenen Funktion setzen. Ich habe es bearbeitet. – rasmeister