I am trying to write a promise function using Bluebird library for nodejs. I want to return 2 variables from my function.
I want the first function to return immediately and the second to complete its own promise chain before returning.
function mainfunction() {
return callHelperfunction()
.then(function (data) {
//do something with data
//send 200 Ok to user
})
.then(function (data2) {
//wait for response from startthisfunction here
})
.catch(function (err) {
//handle errors
});
}
function callHelperfunction() {
return anotherHelperFunction()
.then(function (data) {
return data;
return startthisfunction(data)
.then(function () {
//do something more!
})
});
}
Just like regular functions only have one return value, similarly promises only resolve with one value since it's the same analogy.
Just like with regular functions, you can return a composite value from a promise, you can also consume it using .spread for ease if you return an array:
Promise.resolve().then(function(el){
return [Promise.resolve(1), Promise.delay(1000).return(2));
}).spread(function(val1, val2){
// two values can be accessed here
console.log(val1, val2); // 1, 2
});
The only thing that appears to be wrong is the expectation that do something with data; send 200 Ok to user; should be performed in mainfunction(), part way through the promise chain in callHelperfunction().
This can be overcome in a number of ways. Here's a couple :
1. Move do something with data; send 200 Ok to user; into callHelperfunction()
function mainfunction() {
return callHelperfunction())
.catch(function (err) {
//handle errors
});
}
function callHelperfunction() {
return anotherHelperFunction()
.then(function (data1) {
//do something with data
//send 200 Ok to user
return startthisfunction(data1)
.then(function (data2) {
//wait for response from startthisfunction here
//do something more!
});
});
}
2. Dispense with callHelperfunction() altogether and do everything in mainfunction()
function mainfunction() {
return anotherHelperFunction()
.then(function (data1) {
//do something with data1
//send 200 Ok to user
return startthisfunction(data1);
})
.then(function (data2) {
//wait for response from startthisfunction here
})
.catch(function (err) {
//handle errors
});
}
Related
I want to refresh my indexeddb store with new data after a successful login. After the data refresh is complete, I want to redirect to the landing page. My problem is that I have 1000+ calls to setItem and they aren't finishing.
var app = {
Login: function () {
WebService.Login($("#username").val(), $("#password").val())
.then(function () {
// TODO: refresh data and then redirect...
UpdateData().then(function() {
window.location.href = '/Home';
});
})
.catch(function (err) {
console.log("error logging in");
});
},
UpdateData: function () {
return fetch('/api/Customer').then(function (response) {
return response.json();
})
.then(function (data) {
var customerStore = localforage.createInstance({ name: "customers" });
// Refresh data
customerStore.clear().then(function () {
data.forEach(function (c) {
// How do I know when all setItem calls are complete??
customerStore.setItem(String(c.CustomerID), c);
});
});
})
.catch(function (err) {
console.log("Data error", err);
});
}
}
I'm still relatively new to promises but there must be a way I can get all of the setItem calls into a Promise.all() that I can return. How can I do this?
I think that you need something like this:
return fetch("/api/Customer")
.then(function(response) {
return response.json();
})
.then(function(data) {
var customerStore = localforage.createInstance({ name: "customers" });
// Refresh data
return customerStore.clear().then(function() {
return Promise.all(
data.map(function(c) {
return customerStore.setItem(String(c.CustomerID), c);
})
);
});
})
.catch(function(err) {
console.log("Data error", err);
});
data.map will return an array of promises and then we also return the aggregate promise (from Promise.all).
You should also keep a reference of the customerStore for later use.
Also, if the amount of data is huge, you might want to use localForage-setItems to make the operation a bit more performant (but try to avoid a possible premature optimization).
I am trying to delete a post from a list. The delete function is performing by passing serially to a delete function showed below.
$scope.go = function(ref) {
$http.get("api/phone_recev.php?id="+ref)
.success(function (data) { });
}
After performing the function, I need to reload the http.get request which used for listing the list.
$http.get("api/phone_accept.php")
.then(function (response) { });
Once the function performed. The entire list will reload with new updated list. Is there any way to do this thing.
Try this
$scope.go = function(ref) {
$http.get("api/phone_recev.php?id="+ref)
.success(function (data) {
//on success of first function it will call
$http.get("api/phone_accept.php")
.then(function (response) {
});
});
}
function list_data() {
$http.get("api/phone_accept.php")
.then(function (response) {
console.log('listing');
});
}
$scope.go = function(ref) {
$http.get("api/phone_recev.php?id="+ref)
.success(function (data) {
// call function to do listing
list_data();
});
}
Like what #sudheesh Singanamalla says by calling the same http.get request again inside function resolved my problem.
$scope.go = function(ref) {
$http.get("api/phone_recev.php?id="+ref).success(function (data) {
//same function goes here will solve the problem.
});}
});
You can use $q - A service that helps you run functions asynchronously, and use their return values (or exceptions) when they are done processing.
https://docs.angularjs.org/api/ng/service/$q
Inside some service.
app.factory('SomeService', function ($http, $q) {
return {
getData : function() {
// the $http API is based on the deferred/promise APIs exposed by the $q service
// so it returns a promise for us by default
return $http.get("api/phone_recev.php?id="+ref)
.then(function(response) {
if (typeof response.data === 'object') {
return response.data;
} else {
// invalid response
return $q.reject(response.data);
}
}, function(response) {
// something went wrong
return $q.reject(response.data);
});
}
};
});
function somewhere in controller
var makePromiseWithData = function() {
// This service's function returns a promise, but we'll deal with that shortly
SomeService.getData()
// then() called when gets back
.then(function(data) {
// promise fulfilled
// something
}, function(error) {
// promise rejected, could log the error with: console.log('error', error);
//some code
});
};
I have the following code:
const request = require('request-promise');
request(validateEmailOptions).then(function(result) {
if (result.valid) {
request(createUserOptions).then(function (response) {
if (response.updatePassword) {
request(modifyUserOptions).then(function (response) {
return res.redirect('/signin');
}).catch(function(error) {
return res.redirect('/error');
});
}
}).catch(function(error) {
return res.redirect('/error');
});
} else {
return res.redirect('/error');
}
})
.catch(function (reason) {
return res.redirect('/error');
});
Basically, it's a chain of request call, each one based on the result of the previous call. The problem is that I have many more lines in each condition and as a result, my code is bloated and hard to read and follow. I want to know if there is a better way to write the call chain using request-promises or simply request and bluebird.
You can unnest the promises. Think that this:
f(a).then(function(a) {
return g(b).then(function(b) {
return h(c)
})
})
Is the same as:
f(a).then(function(a) {
return g(b)
}).then(function(b) {
return h(c)
})
I would recommend failing as early as possible, that means handling the error condition first, and having meaningful error messages to be able to log them if need be. Finally, you can propagate the error and handle it in a single catch. To put it in context in your code:
request(validateEmailOptions).then(function(result) {
if (!result.valid) {
throw new Error('Result is not valid');
}
return request(createUserOptions);
}).then(function(response) {
if (!response.updatePassword) {
throw new Error('Password is not updated');
}
return request(modifyUserOptions);
}).then(function(response) {
return res.redirect('/signin');
}).catch(function(error) {
// you may want to log the error here
return res.redirect('/error');
});
as I understand it Angular http has 2 checks 'success and 'error'. Thats in terms of connecting to the service or not - so I have that in hand and thats my first check.
The issue I have is that the data in my JSON has a success state which informs me if the data it contains or has received from my form had any problems with it, in which case there will be an error object that I act on and display to the user.
I need to check for that value of success, but where is the best place to check for that?
Should I be doing it in the controller?
Without that data being correct theres nothing else for the page to do so it is effectively the first thing that needs to be done after the data is retrieved.
heres the basic controller layout
app.controller("dataCtrl", function ($scope, $http) {
$http.post('/getdata').success(function (data) {
$scope.businessData = data;
// Should I then be checking businessData.success at this level?
}).error(function () {
alert("Problem");
});
});
You can write something like this:
$http.post('/getdata').success(function (data) {
if (validate(data)) {
$scope.businessData = data;
} else {
$scop.buisnessDataError = {msg: 'smth bad happend'};
}
}).error(function () {..})
Otherwise, you can write your validator in Promise-like style and then just chain promises in such manner:
$http.post('/getdata').then(function (res) {
return validator(null, res.data);
}, function (err) {
return validator({msg: 'error'})
}).then(function (data) {
//proceed your data
}, function (err) {
alert(err.msg);
});
Where validator is:
var varlidator = function (err, data) {
return $q(function (resolve, reject) {
if (/*data is not valid*/ || err) {
reject(err);
} else {
resolve(data);
}
});
}
$q is a standard angulars implementation of Promises
I have a function which creates a deferred object. On fail I'm calling a fallback function, which in turn creates and returns it's own deferred/promise object. I would like to return the result of this fallback-deferred but I'm only able to return the error on my initial call.
Here is what I'm doing:
// method call
init.fetchConfigurationFile(
storage,
"gadgets",
gadget.getAttribute("data-gadget-id"),
pointer
).then(function(fragment) {
console.log("gotcha");
console.log(fragment);
}).fail(function(error_should_be_fragment) {
console.log("gotcha not");
console.log(error_should_be_fragment);
});
My fetchConfiguration call tries to load from localstorage and falls back to loading from file if the document/attachment I need is not in localstorage.
init.fetchConfigurationFile = function (storage, file, attachment, run) {
return storage.getAttachment({"_id": file, "_attachment": attachment})
.then(function (response) {
return jIO.util.readBlobAsText(response.data);
})
.then(function (answer) {
return run(JSON.parse(answer.target.result))
})
.fail(function (error) {
// PROBLEM
console.log(error);
if (error.status === 404 && error.id === file) {
return init.getFromDisk(storage, file, attachment, run);
}
});
};
My problem is I can catch the 404 allright, but instead of returning the error object, I would like to return the promise generated by init.getFromDisk.
Question:
Is it possible to return the result of my getFromDisk call in the error handler? If not, how would I have to structure my calls so that I'm always returning a promise to my first method call?
Thanks for help!
SOLUTION:
Thanks for the help! Fixed it like this:
init.fetchConfigurationFile(
storage,
"gadgets",
gadget.getAttribute("data-gadget-id"),
pointer
).always(function(fragment) {
console.log("gotcha");
console.log(fragment);
});
init.fetchConfigurationFile = function (storage, file, attachment, run) {
return storage.getAttachment({"_id": file, "_attachment": attachment})
.then(function (response) {
return jIO.util.readBlobAsText(response.data);
})
.then(
function (answer) {
return run(JSON.parse(answer.target.result));
},
function (error) {
if (error.status === 404 && error.id === file) {
return init.getFromDisk(storage, file, attachment, run);
}
}
);
};
.fail() always returns the original promise.
You should call then() with a failure callback to allow chaining:
.then(undefined, function(error) {
return ...;
});
Before jQuery 1.8, use .pipe() instead.