I am new to Javascript and AngularJS, I am trying to figure this out.
I made an angular service that execute DB queries and return promise.
executeStatement = function(db, sql, values, onsuccess, onerror) {
if (!!db.executeSql) {
return db.executeSql(sql, values || [], onsuccess, onerror);
} else {
return db.transaction(function(tx) {
return tx.executeSql(sql, values, function(ignored, rs) {
return onsuccess(rs);
}, function(ignored, error) {
return onerror(error);
});
});
}
};
this.executeStatement = function(sql, values) {
$ionicPlatform.ready( function() {
return new Promise(function(resolve, reject) {
return executeStatement(myDB, sql, values, resolve, reject);
});
} );
}
And then If I call the executeStatement like this in the angular service module.
this.extract = function(callback) {
_DB.executeStatement('SELECT * FROM FRIDGE', []).then(callback);}
Shouldn't this return a promise after the functions are finished running?
I'm getting undefined :(
Some help would be appreciated!
The this.executeStatement() function needs to return the result of $ionicPlatform.ready():
this.executeStatement = function(sql, values) {
return $ionicPlatform.ready( function() {
return new Promise(function(resolve, reject) {
return executeStatement(myDB, sql, values, resolve, reject);
});
} );
}
Now you can access whatever's returned from executeStatement in your callback, which you can pass in as the argument to the .then() function:
_DB.executeStatement('SELECT * FROM FRIDGE', []).then(callback);
The functions within executeStatement are not Promise, do not need to be returned, where onFulfilled, onRejected of Promise constructor is passed as parameters to a function, if and when onsuccess, onerror are called, the original Promise will be resolved or rejected.
Include second parameter to chained .then() or use .catch() to handle potential errors within Promise chain.
Not sure if $ionicPlatform.ready returns a Promise?
_executeStatement = function(db, sql, values, onsuccess, onerror) {
if (!!db.executeSql) {
// `onsuccess` or `onerror` need to be called for `Promise`
// to be fullfiled; a value needs to be passed to
// `onsuccess` or `onerror` to get the value at `.then()` or `.catch()`
db.executeSql(sql, values || [], onsuccess, onerror);
} else {
db.transaction(function(tx) {
tx.executeSql(sql, values, function(ignored, rs) {
onsuccess(rs);
}, function(ignored, error) {
onerror(error);
});
});
}
};
this.executeStatement = function(sql, values) {
return $ionicPlatform.ready( function() {
return new Promise(function(resolve, reject) {
_executeStatement(myDB, sql, values, resolve, reject);
})
.catch(function(err) {
// handle, pass error here
console.log(err);
return err
})
});
}
this.executeStatement(/* parameters */)
.then(function success(data) {
console.log(data);
}, function err(err) {
console.log(err);
});
Related
I'm using a chain to control flow and can't get promise.map in step2() to wait until all of it's generated promises are resolved.
Here's a visual of the flow I'm trying to achieve.
step1()
step2()
step2()
step2()
step2()
step3()
In step2() I'm using Bluebird's promise.map.
Here's the chain:
step1()
.then(function() { return step2() })
.then(function() { return step3() })
.catch(function() { // handle errors })
Here's my functions for each step:
let step1 = function() {
return new Promise(function(resolve, reject) {
// do stuff
resolve()
})
}
let step2 = function() {
return new Promise(function(resolve, reject) {
things = []
return Promise.map(things, function(thing) {
// load file async with callback
})
resolve()
})
}
let step3 = function() {
return new Promise(function(resolve, reject) {
// do stuff
resolve()
})
}
I've tested the chain with many more steps each with a timeout and it worked as expected with the exception of the promise.map in step2(). What am I doing wrong? :)
The problem is from step 2. Promise.map already return promise, so you can just return it to callee. Then you warp the async function with callback with new Promise.
let step2 = function() {
things = []
return Promise.map(things, function(thing) {
// load file async with callback
return new Promise(function(resolve, reject) {
fileAsyncFunc(thing, function callback(err, data) {
if(err) {
reject(err);
return;
}
resolve(data);
});
});
});
}
You are not calling your resolve callback properly.
let step2 = function() {
things = []
return Promise.map(things, function(thing) {
return new Promise( function( resolve, reject ) {
// load file async with callback
resolve(...)
} )
})
}
In your case resolve() is always called, since you are executing async function for loading the file.
I have a function:
function foo(aString, function(err, callback) {
//does stuff
}
I need to call that function from the middle of a long series of Parse.Promises.
How can I wrap it in a Parse.Promise?
I've tried:
//...
return new Parse.Promise(function(resolve, reject) {
foo(thatString, function(err, data) {
if(err) return reject(err);
resolve(data);
});
});
}).then(function(data) {
//...
and other variations like Parse.Promise.as() instead of new Parse.Promise()
Any help would be appreciated.
You're on the right track, but Parse's promise constructor doesn't take resolve / reject functions. Instead, have your wrapper build and return a promise without params, then invoke that promise's resolve() or reject() methods in the wrapped function's callback, like this:
var wrappedFoo = function(aString) {
var promise = new Parse.Promise();
foo(aString, function(err, data) {
if (err) { promise.reject(err); }
promise.resolve(data);
});
return promise;
};
Call it like this:
wrappedFoo("bar").then(function(data) {
// data will be the data passed to the foo callback
}, function(err) {
// likewise for err
});
I am trying to get all records from a DynamoDB table using promises. The problem is that DynamoDB do not return all items in one call I have to make multiple calls. If LastEvaluatedKey is not null means that I need to make another call with that key to get the remaining records. In my code I am checking that and resolving only after LastEvaluatedKey is null. But the console.log("done") is not being executed.
Here is my code:
function query(params) {
return new Promise(function(resolve, reject) {
docClient.query(params, function(err, data) {
if (err) {
reject(err)
} else {
resolve(data);
}
});
})
}
function getAllRecords(params, combinedData) {
return new Promise(function(resolve, reject) {
query(params)
.then(function(data) {
if(!combinedData) {
combinedData = [];
}
combinedData.push(data.Items);
if(data.LastEvaluatedKey) {
params.ExclusiveStartKey = data.LastEvaluatedKey;
getAllRecords(params, combinedData)
}
else {
resolve(combinedData);
}
})
})
}
getAllRecords(params)
.then(function() {
console.log('done')
})
.catch(function(error) {
console.log(error);
})
It's probably a misconception on how promises work from my part. If someone can give me an idea how to make this work. That would be great.
You've fallen prey to the explicit promise construction antipattern, in which you are manually constructing promises when you don't need to.
Generally the only time you need to use the Promise constructor is when you are converting non-Promise async code to Promise async code. You've already done that in your query() function, so you don't need to use the Promise constructor in your getAllRecords() function.
You should do this instead:
function getAllRecords(params) {
return query(params).then(function (data) {
var items = [data.Items];
if(data.LastEvaluatedKey) {
params.ExclusiveStartKey = data.LastEvaluatedKey;
return getAllRecords(params).then(function (theRest) {
return items.concat(theRest);
});
}
return items;
});
}
I'm trying to recursively call AWS's SNS listEndpointsByPlatformApplication. This returns the first 100 endpoints then a token in NextToken if there are more to return (details: AWS SNS listEndpointsByPlatformApplication).
Here's what I've tried:
var getEndpoints = function(platformARN, token) {
return new models.sequelize.Promise(function(resolve, reject) {
var params = {
PlatformApplicationArn: platformARNDev
};
if (token != null) {
params['NextToken'] = token;
}
sns.listEndpointsByPlatformApplication(params, function(err, data) {
if (err) {
return reject(err);
}
else {
endpoints = endpoints.concat(data.Endpoints); //save to global var
if ('NextToken' in data) {
//call recursively
return getEndpoints(platformARN, data.NextToken);
}
else {
console.log('trying to break out!');
return resolve(true);
}
}
});
});
}
I'm calling it with:
getEndpoints(platformARNDev, null)
.then(function(ret) {
console.log('HERE!');
}, function(err) {
console.log(err);
});
Problem is: the first call happens, then the recursive call happens, and I get the message trying to break out! but the HERE! never gets called. I've got something wrong with how my promises are returning I think.
Grateful for pointers.
The problem is that you try and resolve/reject partially completed query. Here is a complete working example with dummy service. I incapsulated the data grabbing into it's own recursive function and only do resolve/reject when i've completely fetched all the data or stumbled upon an error:
// This is the mock of the service. It yields data and token if
// it has more data to show. Otherwise data and null as a token.
var dummyData = [0, 1, 2, 3, 4];
function dummyAsyncCall(token, callback) {
token = token || 0;
setTimeout(function() {
callback({
dummyDataPart: dummyData[token],
token: (typeof (dummyData[token]) == 'undefined') ? null : (token + 1)
});
});
}
// Here is how you would recursively call it with promises:
function getAllData() {
//data accumulator is sitting within the function so it doesn't pollute the global namespace.
var dataSoFar = [];
function recursiveCall(token, resolve, reject) {
dummyAsyncCall(token, function(data) {
if (data.error) {
reject(data.error);
}
if (!data.token) {
//You don't need to return the resolve/reject result.
resolve(dataSoFar);
} else {
dataSoFar = dataSoFar.concat(data.dummyDataPart);
recursiveCall(data.token, resolve, reject);
}
});
}
return new Promise(function(resolve, reject) {
// Note me passing resolve and reject into the recursive call.
// I like it this way but you can just store them within the closure for
// later use
recursiveCall(null, resolve, reject);
});
}
//Here is the call to the recursive service.
getAllData().then(function(data) {
console.log(data);
});
Fiddle with me
That's because you dont need to return resolve/reject, just call resolve/reject when the recursive call completes. A rough code would look like this
var getEndpoints = function(platformARN, token) {
return new models.sequelize.Promise(function(resolve, reject) {
var params = {
PlatformApplicationArn: platformARNDev
};
if (token != null) {
params['NextToken'] = token;
}
sns.listEndpointsByPlatformApplication(params, function(err, data) {
if (err) {
reject(err);
}
else {
endpoints = endpoints.concat(data.Endpoints); //save to global var
if ('NextToken' in data) {
//call recursively
getEndpoints(platformARN, data.NextToken).then(function () {
resolve(true);
}).catch(function (err) {
reject(err);
});
}
else {
console.log('trying to break out!');
resolve(true);
}
}
});
});
}
(caution: this is just a rough code, may work or may not, but is to give a general idea)
I've added a code snippet below, to support this concept, and it works great, check it out.
i = 0;
$('#output').empty();
function pro() {
return new Promise(function(resolve, reject) {
if (i > 3) {
resolve();
return;
}
window.setTimeout(function() {
console.log(i);
$('#output').append(i).append('<br/>');
i += 1;
pro().then(function() {
resolve()
}).catch(function() {
reject()
});
}, 2000);
});
}
pro().then(function () { $('#output').append("now here"); })
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="output"></div>
I'm trying to return a value from a promise, but I can't. Why it doesn't work?
I get Promise { <pending> } output only.
function
function username() {
return new Promise(function (resolve, reject) {
user.where('id', req.id).fetch().then(function (data) {
data = data.toJSON();
resolve(data);
});
});
}
variable
var r = username().then(function (a) {
return a.username;
});
console.log(r);
If I remove return and put console.log(a.username), it works, but it's not the result I want. I want to put returned value inside r.
EDIT #1
I need to pass my returned values into a view (like below), so I must be able to access them outside of the then() chain.
res.render("frontend/index", {
value1 : value1,
value2 : value2,
value3 : value3
});
EDIT #2
I'm using Express.js
Now I get "Error: Can't set headers after they are sent." error, I hope it's more clear now. When a user tries to access a page, I query the database and pass variables to a view, but there are more than one operation per view (username, post info, comments, etc).
exports.index = function (req, res) {
function username() {
return new Promise(function (resolve, reject) {
user.where('id', req.id).fetch().then(function (data) {
data = data.toJSON();
resolve(data);
});
});
}
username().then(function (b) {
res.render('backend/index', {
username: b.username
});
});
function post() {
return new Promise(function (resolve, reject) {
post.where('id', req.params.postId).fetch().then(function (data) {
data = data.toJSON();
resolve(data);
});
});
}
post().then(function (a) {
res.render('backend/index', {
post: a.post
});
});
};
The .then() function returns a promise only. Here in above code variable r is nothing but a promise reference object.
If you want to use the returned response from the promise, this is how you will do it -
username().then(function (a) {
console.log(JSON.stringify(a));
// you will need to use the response returned from server here..
// display in view or something else
res.render("frontend/index", {
value1 : a.value1,
value2 : a.value2,
value3 : a.value3
});
});
Returning a value from inside a promise thenable function will only return a promise and not the value.
You will need to wait till all the promises are resolved and then only send the response from the server. Once a response is sent, you can not send it again and hence the error headers....
Updated answer as per modified question -
exports.index = function (req, res) {
function username() {
return new Promise(function (resolve, reject) {
user.where('id', req.id).fetch().then(function (data) {
data = data.toJSON();
resolve(data);
});
});
}
function post() {
return new Promise(function (resolve, reject) {
post.where('id', req.params.postId).fetch().then(function (data) {
data = data.toJSON();
resolve(data);
});
});
}
username().then(function (b) {
post().then(function (a) {
res.render('backend/index', {
post: a.post,
username: b.username
});
});
});
};
Try performing next process where fulfilled value of r is used inside of .then() to access asynchronous returned value from Promise r
var r = username().then(function (a) {
return a.username;
});
r.then(function(data) {
// `data` : `r` return value
// do stuff with `data` here
});
You'll have to restrict the usage of the value to functions passed to .then. There is no other logical way to assert that the value of r has been assigned.
var r;
username().then(function(a) {
r = a.username;
// use r here
// resolve promise with value of username
return r;
}).then(function(username) {
// or use it here
});