I am trying to use .all to do an action after all promise got resolved but when I return a promise its just empty.
I am appending all promises to pushPromise and later when I try to do Promise.all(pushPromise) then it wont work.
I tried to console.log(pushPromise) and it shows empty array. Why?
Thanks
var Client = require('ssh2-sftp-client');
var sftp = new Client();
var folderPromise = [];
var toServer = function(dir){
return new Promise(function (resolve, reject){
filePermission(dir, function(){
getAllFiles(dir.replace(/\/$/, ''));
console.log('Got all files');
resolve();
});
}).then(function(done){
arrayfolder.forEach(function(folder){
folder = folder.replace(dir, '');
//console.log(folder);
folderPromise.push(sftp.mkdir(folder, true));
});
return Promise.all(folderPromise).then(function(){
console.log('Folder added');
return 'Done';
});
}).then(function() {
return 'Done';
})
.catch((err) => {
console.log(err);
return 'Not Done';
});
}
var pushPromise = [];
connections.forEach(function(connection){
var dir = getConnectionDir(connection);
pushPromise.push(toServer(dir));
});
console.log(pushPromise); // return []
Promise.all(pushPromise).then(function(){
console.log('All uploaded to server');
});
Problem may be with connections returning an empty array. I tested locally and pushPromise is returning array of promises properly.
Related
I have a promise which return an array of objects from IndexedDB:
const syncData = () => {
return new Promise((resolve, reject)=>{
var all_form_obj = [];
var db = self.indexedDB.open('Test');
db.onsuccess = function(event) {
var db = this.result
// Table new_form
var count_object_store_new_form = this.result.transaction("new_form").objectStore("new_form").count()
count_object_store_new_form.onsuccess = function(event) {
if(count_object_store_new_form.result > 0){
db.transaction("new_form").objectStore("new_form").getAll().onsuccess = function(event) {
var old_form_arr = event.target.result
for(element in old_form_arr){
all_form_obj.push(old_form_arr[element])
}
}
}
}
// Table old_form
var count_object_store_old_form = this.result.transaction("old_form").objectStore("old_form").count()
count_object_store_old_form.onsuccess = function(event) {
if(count_object_store_old_form.result > 0){
db.transaction("old_form").objectStore("old_form").getAll().onsuccess = function(event) {
var old_form_arr = event.target.result
for(element in old_form_arr){
all_form_obj.push(old_form_arr[element])
}
}
}
}
}
db.onerror = function(err) {
reject(err);
}
resolve(all_form_obj)
})
};
After I resolve my array, I call the promise in the sync event:
self.addEventListener('sync', function(event) {
if (event.tag == 'sync_event') {
event.waitUntil(
syncData()
.then((form_arr)=>{
console.log(form_arr)
for(form in form_arr) {
console.log(form_arr)
}
}).catch((err) => console.log(err))
);
}
});
In the 'then' of my promise syncData I print to the console two times.
The first console.log appears in the console (my array of objects) but the second which is in loop (for in) doesn't appear in the console and I don't understand why.
My goal is to be able to loop through each object and send it to my database with fetch but the problem is that the code in the loop doesn't run.
My result of the first console log:
I think resolve is not placed in the desired place and the reason why the 2nd console.log is not showing up is because form_arr is []. I simplified your code to demonstrate why it went []. db.onsuccess and db.onerror were just defined there without being called. To fix this problem, you may want to place resolve inside db.onsuccess and reject inside db.onerror.
const syncData = () => {
return new Promise((resolve, reject)=>{
var all_form_obj = [];
var db = self.indexedDB.open('Test');
db.onsuccess = function(event) {
// ... will be called async
resolve(all_form_obj)
}
db.onerror = function(err) {
// ... will be called async
}
// remove resolve here
})
};
I need to:
1) Make two request
2) Then take data from requests
3) And send response
I am using firebase database. I am taking data from database by forEach
I need to process data and response data(json)
Can anyone help me with asynchronous? Or help write callback function
I read a lot of information about this, but dont understant
My code here works not fine
I have problems with asynchronous
So how can I improve it?
router.get('/places/all', function(req, res, next) {
var lat = req.param('lat');
lon = req.param('lon');
result = [],
resData = [];
var query = firebase.database().ref('Places');
var i = 0;
var promise1 = new Promise(function(resolve, reject) {
query.on("value", function(snapshot) {
console.log(snapshot.numChildren())
snapshot.forEach(function(childSnapshot) {
childData = childSnapshot.val();
var gmapApiKey = 'API_KEY';
placeID = childData.placeID;
language = req.param('lang');
url = 'https://maps.googleapis.com/maps/api/place/details/json?placeid=' + placeID + '&key=' + gmapApiKey + '&language=' + language;
placeLat = childData.lat;
placeLon = childData.lon;
distanceMatrixApiUrl = 'https://maps.googleapis.com/maps/api/distancematrix/json?origins=' + lat + ',' + lon + '&destinations=' + placeLat + ',' + placeLon + '&key=' + gmapApiKey;
i++;
var requestDistance = new Promise(function(resolve, reject) {
https.get(distanceMatrixApiUrl, res => {
res.setEncoding("utf8");
let body = "";
res.on("data", data => {
body += data;
});
res.on("end", () => {
body = JSON.parse(body);
resolve(body);
});
});
console.log(requestDistanceApi)
requestDistance = Promise.resolve(requestDistanceApi)
});
var requestPlaces = new Promise(function(resolve, reject) {
https.get(url, res => {
res.setEncoding("utf8");
let body = "";
res.on("data", data => {
body += data;
});
res.on("end", () => {
i++;
result = JSON.parse(body);
resolve(result);
});
});
console.log(requestPlaceApi)
requestPlaces = Promise.resolve(requestPlacesApi)
i++;
});
requestDistance.then(function(valueDistance) {
requestPlaces.then(function(valuePlace) {
resData.push({
name: valuePlace.result.name,
address: valuePlace.result.vicinity,
open_now: valuePlace.result.opening_hours.open_now,
weekday_text: valuePlace.result.opening_hours.weekday_text,
latitude: valuePlace.result.geometry.location.lat,
longitude: valuePlace.result.geometry.location.lng,
distance: valueDistance.rows[0].elements[0].distance.text,
});
}).catch((error) => {
assert.isNotOk(error,'Promise Places error');
done();
});
}).catch((error) => {
assert.isNotOk(error,'Promise Distance error');
done();
});
});
});
});
promise1.then(function(value) {
res.send(value);
}).catch((error) => {
assert.isNotOk(error,'Promise error');
done();
});
});
I'm not going to rewrite this all but rather will give you an outline.
First of all the firebase SDK has promises available in lieu of using callbacks. Use those instead of adding new Promise to wrap them. This will help streamline the code structure and enable making the whole promise chain simpler
I'm not sure which package htts.get() comes from but it too likely has promises. Convert to using those also
The other trick will be to combine the 2 nested requests into one promise which can be done using Promise.all()
So here's the basic code outline. Note that I have not paid a lot of attention to exactly how you want all this data processed in order to send to client. You will need to adjust as needed
You probably want to break this whole code block down into smaller functions also to make the logic easier to follow
Also note I have not added any error handling catch()s which is going to be up to you
// use firebase promise instead of callback
var mainpromise = query.on("value").then(function(snapshot) {
var subPromises = [];
snapshot.forEach(function(childSnapshot) {
//childData = ...
// look into https promises instead of wrapping in `new Promise
var placesPromise new Promise(function(resolve, reject) {
https.get(distanceMatrixApiUrl, res => {
// .....
res.on("end", () => {
body = JSON.parse(body);
resolve(body);
});
});
});
var distancePromise = new Promise.... // similar to above
// combine these promises into one
var combinedPromise = Promise.all([placesPromise, distancePromise]).then(function(resultsArray) {
var places = resultsArray[0],
distances = resultsArray[1];
//assign above to childData or whatever you want to do with them
return childData;// or return processed results or skip this `then and do all processing in the next then() commented below
})
// store combined promises in array
subPromises.push(combinedPromise);
});
// return promise to resolve mainPromise
return Promise.all(subPromises)// might need a `then()` here to return processed data depending on structure you want returned
});
mainPromise.then(function(results) {
// process and send results which is array of all the childData from snapshot.forEach
res.send(processedData);
})
Here is my code:
var gblink = require('./getbloglinks');
new Promise(function (resolve, reject) {
var getLinks = gblink.getBlogLinks("www.example.com");
resolve(getLinks);
}).then(function (data) {
console.log("here");
console.log(data);
return false;
})
gblink.getBlogLinks() is a function which gets a URL and returns all links in that page (after a short time). When I run my code, immediately console.log("here"); will be printed and then console.log(data); will be printed as undefined.
Anyway how can I make that promise waiting until the result of getBlogLinks() returns?
Noted that when I call gblink.getBlogLinks() function manually, it works as well, it just takes a while and all I need to do now is implementing a waiting system for that function.
Here is gblink.getBlogLinks():
const NN = require('nightmare');
exports.getBlogLinks = function (data){
const n = NN({show:true});
n.goto(data)
.evaluate(() => {
var data = document.querySelectorAll("a[target='_blank']");
arr = [];
i=0;
Array.from(data).forEach( function(x){
arr[i] = x.href;
i++;
});
return arr;
})
.then((data) => {
return n.end(data);
})
}
getBlogLinks is not returning the promise. Doing that should solve the problem.
const NN = require('nightmare');
exports.getBlogLinks = function (data){
const n = NN({show:true});
return n.goto(data)
.evaluate(() => {
var data = document.querySelectorAll("a[target='_blank']");
arr = [];
i=0;
Array.from(data).forEach( function(x){
arr[i] = x.href;
i++;
});
return arr;
})
.then((data) => {
n.end(data);
return data;
})
};
Edited:
var gblink = require('./getbloglinks');
new Promise(function (resolve, reject) {
var getLinks = gblink.getBlogLinks("www.example.com");
console.log(getLinks);//========= Here You will get Pending promise =========
resolve(getLinks);
}).then(function (data) {
console.log("here");
console.log(data);//========= Here You will get the array=========
return false;
})
Edited2:
var gblink = require('./getbloglinks');
/*
new Promise(function (resolve, reject) {
var getLinks = gblink.getBlogLinks("www.example.com");
console.log(getLinks);//========= Here You will get Pending promise =========
resolve(getLinks);
})*/
//Below is recommended way to chain the promise, avoid promise constructor, if not needed
gblink.getBlogLinks("www.example.com")
.then(function (data) {
console.log("here");
console.log(data);//========= Here You will get the array=========
return false;
})
I am assuming that getBlogLinks() is a function implemented in your scope of development.
So, what is happening, in your current code of getBlogLInks() the response is getting returned only when there is a response. But the way you call it, it's synchronous.
Your getBlogLinks need to be wrapped in a promise.
getBlogLinks(data) {
return new Promise( function(resolve,reject) {
....all your function code
.then(data) {
resolve(data);
}
});
}
then use getBlogLinks().then and you will have your answer
I have an AngularJS application, which I use promises to get data from firebase database.
Here is my home-controller:
$scope.wallets;
walletDAO.getWalletsByUserId(auth.uid)
.then(function(wallets){
$scope.wallets = wallets;
$scope.$apply();
})
.catch(function(error){
console.log(error);
});
These are my two methods inside an service I call walletDAO:
this.getWalletsByUserId = function(id) {
return new Promise(function(resolve, reject) {
//codigo aqui
var dbRef = database.ref("users/" + auth.currentUser.uid);
dbRef.on('value', function(data) {
//console.log("Wallet IDs Retrieved!");
var userOnDB = data.val();
var walletIds = userOnDB.wallets;
var wallets = [];
for (i = 0; i < walletIds.length; i++) {
var x = getWalletById(walletIds[i])
.then(function(wallet){
wallets.push(wallet);
})
.catch(function(error){
console.log(error);
});
}
resolve(wallets);
}, function(error) {
reject(error);
});
});
};
var getWalletById = function(id) {
return new Promise(function(resolve, reject) {
var dbRef = database.ref("wallets/" + id);
dbRef.on('value', function(data) {
//console.log("Wallet Retrieved!");
var wallet = data.val();
//console.log(wallet);
resolve(wallet);
}, function(error) {
reject(error);
});
});
};
The second method, getWalletById, receive an wallet ID and return an wallet object from the firebase database. this mehod is called on the first method, getWalletsByUserId inside a for loop, which should wait for the second method to return the wallet before iterate to the next, so it can push it into the array. The problem is that it dont wait and the code execute the .then() method on the home-controller before the resolving of the getWalletById, leaving the $scope.wallets empty.
Any advice?
Use $q.all() to wait for all sub-promises to complete
$q.all(walletIds.map(function(id){
return getWalletById(id);
})).then(function(wallets){
...
})
Instead of manufacturing an ES6 promise from the ref.on method, use the ref.once method and bring it into the AngularJS execution context with $q.when:
function getWalletById(id) {
var dbRef = database.ref("wallets/" + id);
var es6Promise = dbRef.once('value');
return $q.when(es6Promise);
}
Only operations which are applied in the AngularJS execution context will benefit from AngularJS data-binding, exception handling, property watching, etc.
Use $q.all and promise chaining in the parent function:
this.getWalletsByUserId = function(id) {
var dbRef = database.ref("users/" + auth.currentUser.uid);
var es6Promise = dbRef.once('value')
.then(function(snapshot)
//console.log("Wallet IDs Retrieved!");
var userOnDB = snapshot.val();
var walletIds = userOnDB.wallets;
var promiseList = walletIds.map(function(id){
return getWalletById(id);
});
return $q.all(promiseList);
});
return $q.when(es6Promise);
};
The .then method returns a new promise which is resolved or rejected via the return value of the successCallback, errorCallback (unless that value is a promise, in which case it is resolved with the value which is resolved in that promise using promise chaining).
In the method "myMethod" of my "gulpfile.js" I want to create multiple Promises. The quantity depends on the array size (method parameter). When I call the method I want to make sure that all promises are fulfilled before I continue. I would prefer to return not before all promises are fulfilled.
Please have a look at the last five lines of code.
Dependencies
var promiseAll = require('gulp-all');
var del = require('del');
var deleteEmpty = require('delete-empty');
gulp-all | del | delete-empty
Helper Method
var oneForAllPromises = function(promises){
var promAll = promiseAll(promises);
promAll.then(function(param) {
console.log('foo');
}, function(err) {
console.error('foo');
});
return promAll;
}
Problematic Code
var myMethod = function(array1, array2){
var promise = del(array1, {force: true});
promise.then(paths => {console.log('foo');});
var promises = [];
promise.then(()=>{
for(var i=0; i<array2.length; i++){
promises[i] = new Promise(function(resolve, reject) {
deleteEmpty(array2[i], {force: true},
function(err, deleted){
if(err){
console.log('foo');
reject
}else{
console.log('foo');
resolve
}
}
);
});
}
});
// PROBLEM: Returns empty promises array
console.log("promiesesLENGTH: "+promises.length); // promiesesLENGTH: 0
// Create one promise for all the promises
return oneForAllPromises(promises);
}
At the time of the console.log, the first promise promise = del(array1, {force: true}); is not yet finished, so none of the code in the then is yet executed. That's why your promises are empty.
You can simply return in a then another promise:
var myMethod = function(array1, array2){
var promise = del(array1, {force: true});
return promise.then(() => {
return Promise.all(array2.map(array2value => {
return new Promise(function(resolve, reject) {
deleteEmpty(array2value, {force: true}, (err, deleted) => {
if (err) {
reject(err);
} else{
resolve()
}
});
});
}
});
}