2015-03-21 5 views
8

Ich versuche derzeit, zu einem Array (Attribut innerhalb eines Mongo-Modells), aus einer Liste von Elementen, die ich durch eine Anfrage erhalten. Von diesen Elementen durchlaufe ich sie, um zu sehen, welches gerade in der Datenbank ist, und wenn das nicht der Fall ist, erstelle ich ein neues Element und versuche es zu speichern. Ich verwende Versprechungen, um diese Aufgabe zu erfüllen, aber ich kann nicht herausfinden, warum das Array leer ist, nachdem alle Versprechen erfüllt wurden.Node.js Versprechen: Push to Array asynchron & speichern

var q  = require('q'); 

var items_to_get = ['1', '2', '3']; // example array 

var trans = new Transaction({ 
    items : [] 
}); 

var promises = []; 

for (var i = 0; i < items_to_get.length; i++) { 

    var ith = i; //save current i, kinda hacky 
    var deferred = q.defer(); //init promise 

    //find an existing item 
    Item.findOne({simcode: items_to_get[ith]}, function(err, item) { 
     trans.items.push(item); // push item to transaction 
     deferred.resolve(item); // resolve the promise 
    }); 
    promises.push(deferred); // add promise to array, can be rejected or fulfilled 
}; 

q.allSettled(promises).then(function(result) { 
    console.log(trans.items); //is empty 
    trans.save(); 
} 

EDIT gelöst: Code unten, basierend auf http://jsbin.com/bufecilame/1/edit?html,js,output .. gehen Credits

var items_to_get = ['1', '2', '3']; 
var promises  = []; //I made this global 

items_to_get.forEach(item) { 
    upsertItem(item); 
} 

q.allSettled(promises).then(function(result) { 
    //loop through array of promises, add items 
    result.forEach(function(res) { 
    if (res.state === "fulfilled") { 
     trans.items.push(res.value); 
    } 
    }); 
    trans.save(); 
    promises = []; //empty array, since it's global. 
} 

//moved main code inside here 
function upsertItem(item) { 
    var deferred = q.defer(); //init promise 
    //find an existing item 
    Item.findOne({simcode: item}, function(err, item) { 
    deferred.resolve(item); // resolve the promise 
    // don't forget to handle error cases 
    // use deffered.reject(item) for those 
    }); 
    promises.push(deferred); // add promise to array 
} 

Antwort

0

Statt

promises.push(deferred); 

@macqm ... versuchen ...

promises.push(deferred.promise); 

Da auch Ihre Versprechen auf das Element aufgelöst, die ohnehin gespeichert wurde, können Sie das Ergebnis von q.allSettled(...) als Elemente verwenden:

q.allSettled(promises).then(function(results) { 
    trans.items = results; 
    trans.save(); 
}); 
+1

Scheint, dass jedes Ergebnis ein Objekt der '{state: ..., value: ...}' Struktur ist, wobei 'value' ein gewünschtes Element ist, also müssen Sie möglicherweise einen zusätzlichen Schritt ausführen die raus. – macqm

2

Dies ist, wie ich es ohne 3rd-Party-Bibliotheken haben.

Da musste ich nur verschieben und ich bin auf ES2017 Ich dachte, es war am besten, Dinge mit unnötigen Abhängigkeiten nicht zu komplizieren.

'use strict'; 

/** 
* @param {function(*)} callee 
* @param {Array} args 
* @returns {Promise.<*>} 
*/ 
const defer = (callee, args) => { 
    return new Promise(resolve => { 
     resolve(callee(...args)); 
    }); 
}; 

/** 
* @param {Number} one 
* @param {Number} two 
* @param {Number} timeout 
* @returns {Promise.<Number>} 
*/ 
const asyncFunction = (one, two, timeout) => { 
    return new Promise(resolve => { 
     setTimeout(resolve, timeout, one + two); 
    }); 
}; 

let promises = []; 
promises.push(defer(asyncFunction, [3, 7, 0])); // returns immediately 
promises.push(defer(asyncFunction, [10, 20, 100])); // returns after 100ms 
promises.push(defer(asyncFunction, [55, 45, 50])); // returns after 50ms 

Promise.all(promises).then(results => { 
    console.log(results); 
}); 

Führen Sie den obigen Code und Sie werden [ 10, 30, 100 ] erhalten.

+0

Danke mann !!!!!!!!! – Vesper