Javascript promise not delaying function execution - javascript

I'm using ES6 javascript promises in Chrome and am having trouble understanding why the promise executed within the function _getStatus() is not returning the result argument in the success handler which would result in the alert box containing "done". Instead, I get an alert box that says "undefined".
myNameSpace = function(){
var obj = {
groupA: {
status: "inactive"
},
groupB: {
status: "active"
}
};
function _getStatus(group){
_finishTask().then(function(result){
return result; // doesn't return anything
});
}
function _finishTask(){
var promise = new Promise(function(resolve, reject){
// do some task before resolving
resolve("done");
});
return promise;
};
return{
getStatus:_getStatus
}
}();
$(function(){
alert(myNameSpace.getStatus("groupA")); // why is this "undefined" instead of "done"?
});

Because this is not how Promises work. You need to make sure both _getStatus and _finishTask return Promise objects. Then you will be able to use those promises API methods to execute subsequent code what promise is resolved.
So your code should look something like this:
myNameSpace = function() {
var obj = {
groupA: {
status: "inactive"
},
groupB: {
status: "active"
}
};
function _getStatus(group) {
return _finishTask().then(function(result) {
return result + " and tested";
});
}
function _finishTask() {
return new Promise(function(resolve, reject) {
// do some task before resolving
resolve("done");
});
};
return {
getStatus: _getStatus
}
}();
myNameSpace.getStatus("groupA").then(alert);
Finally, regarding this construction:
return _finishTask().then(function(result) {
return result;
});
_finishTask returns a Promise object, when this promise is resolved you get into then callback. Whatever value you return from this callback becomes a new resolution value for the subsequent success callbacks down the resolution chain.
Demo: http://plnkr.co/edit/K1SWKuTYA3e46RxdzkCe?p=preview

You cant return a result from an asynchronous function as the code running it has already finished by the time the response is returned.
You can however pass in a callback to execute once the code is complete:
function _getStatus(group, callback){
_finishTask().then(function(result){
callback(result);
});
}
$(function(){
myNameSpace.getStatus("groupA", function(result) {
alert(result);
});
});
or use the promise api itself (in this case your _getStatus method is a little redundant):
function _getStatus(group){
return _finishTask();
}
$(function(){
myNameSpace.getStatus("groupA").then(function(result) {
alert(result);
});
});

Related

Why can I return a recursive run of promises?

I have the following code (reconstructed almost 1:1 to work in here):
First of all, understand that bridge_component_start_test is really a call to a constructor object where we generate the initial promise by return new Promise.. I tried to mimick this here. It's my factory for AJAX calls, so, each object creates a promise, which makes a call, which then resolves / rejects with the JSON that it received from the server. I've emulated that response in the resolves below as well.
function recursive_function(data) {
let local_data = $.extend({}, data);
return new Promise((resolve, reject) => {
//The offset gets
local_data.bridge_process_batch_offset++;
if (local_data.bridge_process_batch_offset == 3) {
resolve({
'data': {
'response_data': {
'done_batching': true
}
},
'success': true
})
} else {
resolve({
'data': {
'response_data': {
'done_batching': false,
'bridge_process_batch_offset': local_data.bridge_process_batch_offset
}
},
'success': true
})
}
//For now, no reject.
});
}
function do_the_main_thing(data) {
/**
* Make a local copy of the passed data.
*/
let request_data = $.extend({}, data);
let bridging_data = {
'just_installed_component_demo': request_data.just_installed_component_demo,
'just_installed_component_name': request_data.just_installed_component_name,
'just_installed_component_category': request_data.just_installed_component_category,
'bridge_process_batch_offset': 0
};
const recursively_do_things = () => recursive_function(bridging_data).then(response => {
if (response.data.response_data.done_batching) {
return (response);
} else if (response.data.success == false) {
return response;
} else {
console.log('Went through step ' + response.data.response_data.bridge_process_batch_offset + '!');
if ('bridge_process_batch_offset' in response.data.response_data) {
bridging_data.bridge_process_batch_offset = response.data.response_data.bridge_process_batch_offset;
}
return recursively_do_things ();
}
}).catch(error => {
return error;
});
return recursively_do_things();
}
do_the_main_thing({
'just_installed_component_demo': 'demo-2',
'just_installed_component_name': 'demo-2_post',
'just_installed_component_category': 'post',
'bridge_process_batch_offset': 0
}).then(response => {
console.log('...and now I am done!');
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
But notice, in my do_the_main_thing I'm merely returning the response from that promise recursion. Yes, surely, I also return recursively_bridge_component_start but how does JS know to return a promise out of that recursive functionality?
A return is a return. It doesn't have to wait for the Promise to finish, yet it seems it does. In theory, my last line of return recursively_do_things should just instantly return before the Promises are done.
What am I missing here?
But it's quite straightforward. The return value of bridge_component_start_in_test(data) is the return value of recursively_bridge_component_start().
That function in turn returns bridge_component_start_test(data).then(/* do stuff */).catch(/* do other stuff */). That will always be a promise regardless of details of "do stuff" and "do other stuff".
And bridge_component_start_test explicitely returns a promise: return new Promise(//...
You are not returning merely response from recursively_do_things
If you look at the function, you are returning a part of the chain, your return response is just part of the promise chain.
So this part
const recursively_do_things= () => recursive_function(bridging_data).then(response => /* omitted */ );
is returning you a promise chain implying that it first waits for recursive_function to complete, and then does the inner response, after which you can chain other statements
so, since you are returning return recursively_do_things() from your do_the_main_thing(data), it is clear that a promise will be returned.
Update based on comment
Promises are promise aware themselves, which means that if you return a promise in a chain, the promise chain will wait for the returned promise to complete before continuing the next part of the chain.
The requirement for that is that you need to return it, if you just call a function that returns a promise, it will not wait for it.

Retrieve data from callback function if this function is of return type

function getPageDetails(callback,filterlink) {
var message=1+2;
callback(message,filterlink);
});
};
function test(message,filterlink)
{
var data=message+1;
return data
}
function test1(filterlink)
{
var testdata=getPageDetails(test,filterlink)
alert(testdata)
}
In this example, when I call test1(filterlist) method with a parameter and want to call a callback function. I did get any data in testdata variable. It should be 4 in alert. Can anyone help?
Your function getPageDetails isn't returning anything.
While executing callback(message, filterlink) you need to return it's result so var testdata will get the value assigned :
function getPageDetails(callback, b) {
[...]
return callback(...);
}
make use of promise , that will resolve your issue
let p1 = new Promise(
(resolve, reject) => {
log.insertAdjacentHTML('beforeend', thisPromiseCount +
') Promise started (<small>Async code started</small>)<br/>');
// This is only an example to create asynchronism
window.setTimeout(
function() {
// We fulfill the promise !
resolve(thisPromiseCount);
}, Math.random() * 2000 + 1000);
}
);
// We define what to do when the promise is resolved with the then() call,
// and what to do when the promise is rejected with the catch() call
p1.then(
// Log the fulfillment value
function(val) {
log.insertAdjacentHTML('beforeend', val +
') Promise fulfilled (<small>Async code terminated</small>)<br/>');
})
.catch(
// Log the rejection reason
(reason) => {
console.log('Handle rejected promise ('+reason+') here.');
});
Full info about : promise
If you return the callback like suggested in the comments and remove the }); in the first function it works.
I highly reccomend you to use the solution of Pranay Rana as it is much better. It's worth to invest in the understanding of promises if you work with js!
function getPageDetails(callback, filterlink) {
var message = 1 + 2;
return callback(message, filterlink);
}
function test(message, filterlink) {
var data = message + filterlink;
return data
}
function test1(filterlink) {
var testdata = getPageDetails(test, filterlink)
alert(testdata)
}
test1(1);

jQuery .done not returning as expected

I know this is a misunderstanding on my part and i'm trying to learn what i'm doing wrong and I could really use some help please.
I have an ajax request that is succeeding and returning data just fine. The Api returns an error code, then I try to return a response based on what code I was given, except that the function is only returning what the ajax call delivered.
function getData(){
var promise = $.ajax({
url: 'api.php',
type: 'POST',
dataType: 'json'
});
return promise.done(function(data){
console.log(data);
if(data.errorCode === 0){
return data;
} else {
return 'failed';
}
});
}
$(document).ready(function(){
$('.btn').click(function(){
var apiData = getData();
console.log(apiData);
});
});
So if the api returns an error code that is not 0 then the function getData should return a string of 'failed', except it returns the data element. I know that the code is not 0 because the console.log shows that the code is 999. What am I doing wrong? Why I can't I get it to return my string of "failed" ?
getData doesn't (and can't) return the data or "failed"; it returns a promise. You consume that promise much the way you did inside getData:
$(document).ready(function(){
$('.btn').click(function(){
getData().done(function(apiData) { // **
console.log(apiData); // **
}); // **
});
});
In that callback, apiData will be whatever your callback in getData returned, so it'll be the data object or the string "failed".
(I've used done there because it's what you used elsewhere, but normally I'd use then, the standard promise function.)
One of the key things to understand about promises is that then (and done) returns a new promise (technically, with real promises, a thenable) that will be settled based on what the callback does.
So consider (let's stick with jQuery's Deferred for now):
function doSomething() {
var d = $.Deferred();
setTimeout(function() {
// Resolve our promise with "a"
d.resolve("a");
}, 10);
return d.promise();
}
// Consume the promise and put it through a chain:
doSomething()
.then(function(result) {
// This callback happens to do synchronous processing
console.log("First callback got", result);
return result.toUpperCase();
})
.then(function(result) {
// This one does something async, and so it returns a promise
var cd = $.Deferred();
setTimeout(function() {
console.log("Second callback got", result);
cd.resolve(result + result);
}, 10);
return cd.promise();
})
.then(function(result) {
console.log("Third callback got", result);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
The output of that is
First callback got a
Second callback got A
Third callback got AA
Now, earlier I said then always returns a promise (thenable). How does it do that when my first callback is synchronous and returns a value directly, but my second one is async and returns a promise? The then function looks at the return value from the callback and, if it's "thenable" (something with then on it), returns it; if it's not thenable, it creates a new, resolved promise with the value as the resolution value.
Just for completeness, here's the example above with native JavaScript promises (requires browser support):
function doSomething() {
return new Promise(function(resolve) {
setTimeout(function() {
// Resolve our promise with "a"
resolve("a");
}, 10);
});
}
// Consume the promise and put it through a chain:
doSomething()
.then(function(result) {
// This callback happens to do synchronous processing
console.log("First callback got", result);
return result.toUpperCase();
})
.then(function(result) {
// This one does something async, and so it returns a promise
return new Promise(function(resolve) {
setTimeout(function() {
console.log("Second callback got", result);
resolve(result + result);
}, 10);
});
})
.then(function(result) {
console.log("Third callback got", result);
});
The output of that is
First callback got a
Second callback got A
Third callback got AA
According to http://api.jquery.com/jquery.ajax/ documentation, you can either chain .done, .fail, .always or .then.
$(document).ready(function() {
$('.btn').click(function() {
$.ajax({
url: 'api.php',
type: 'POST',
dataType: 'json'
})
.done(function(data) {
console.log(data);
if (data.errorCode === 0) {
console.log(data)
} else {
console.log(data)
}
});
});
});
This will work

While loop in promise until another promise ends

I need to test with REDIS (which work asynchronously) if a value is set or not before letting my code to run.
I started to work with Loop Promise as defined here : https://stackoverflow.com/a/17238793/3912805
I've tried this but unfortunately I'm stuck with a promise in pending :
promise: { state: 'pending' }
function promiseWhile(condition, body) {
var done = Q.defer();
function loop() {
/** When the result of calling condition is no longer true, we are done */
if(!condition())
return done.resolve();
/** Use 'when', in case `body` does not return a promise */
/** When it completes loop again otherwise, if it fails, reject the done promise */
Q.when(body(), loop, done.reject);
}
/** Start running the loop in the next tick so that this function is completely async */
/** It would be unexpected if body was called synchronously the first time */
Q.nextTick(loop);
return done.promise;
}
var timeline_id = 3;
promiseWhile(function () {
return Q.ninvoke(redisClient, 'hget', 'hashTest', timeline_id).then(function (result) {
console.log(result + '<---->');
return result;
});
}, function () {
return Q.delay(500);
}).then(function () {
// Let's continue process...
});
I need to check in intervals, cause if a timeline_id is already in process, I need to wait UNTIL timeline_id has been removed on Redis from hashTest.
How can I be sure I got result rather than promise state to check if I can still run my loop or not.
Finally, I found a way to achieve this...
for sure not really elegant, but I can't do better for now :
var redisState = true;
promiseWhile(function () {
/** Loop until true */
return redisState;
}, function (result) {
return Q.ninvoke(redisClient, 'HGET', 'hashTest', timeline_id).then(function(result) {
redisState = result;
if (redisState) {
redisState = result;
return Q.delay(500);
}
});
}).then(function() {
...
}):

Return from a promise then()

I have got a javascript code like this:
function justTesting() {
promise.then(function(output) {
return output + 1;
});
}
var test = justTesting();
I have got always an undefined value for the var test. I think that it is because the promises are not resolved yet..there is a way to return a value from a promise?
When you return something from a then() callback, it's a bit magic. If you return a value, the next then() is called with that value. However, if you return something promise-like, the next then() waits on it, and is only called when that promise settles (succeeds/fails).
Source: https://web.dev/promises/#queuing-asynchronous-actions
To use a promise, you have to either call a function that creates a promise or you have to create one yourself. You don't really describe what problem you're really trying to solve, but here's how you would create a promise yourself:
function justTesting(input) {
return new Promise(function(resolve, reject) {
// some async operation here
setTimeout(function() {
// resolve the promise with some value
resolve(input + 10);
}, 500);
});
}
justTesting(29).then(function(val) {
// you access the value from the promise here
log(val);
});
// display output in snippet
function log(x) {
document.write(x);
}
Or, if you already have a function that returns a promise, you can use that function and return its promise:
// function that returns a promise
function delay(t) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve();
}, t);
});
}
function justTesting(input) {
return delay(100).then(function() {
return input + 10;
});
}
justTesting(29).then(function(val) {
// you access the value from the promise here
log(val);
});
// display output in snippet
function log(x) {
document.write(x);
}
What I have done here is that I have returned a promise from the justTesting function. You can then get the result when the function is resolved.
// new answer
function justTesting() {
return new Promise((resolve, reject) => {
if (true) {
return resolve("testing");
} else {
return reject("promise failed");
}
});
}
justTesting()
.then(res => {
let test = res;
// do something with the output :)
})
.catch(err => {
console.log(err);
});
Hope this helps!
// old answer
function justTesting() {
return promise.then(function(output) {
return output + 1;
});
}
justTesting().then((res) => {
var test = res;
// do something with the output :)
}
I prefer to use "await" command and async functions to get rid of confusions of promises,
In this case I would write an asynchronous function first,
this will be used instead of the anonymous function called under "promise.then" part of this question :
async function SubFunction(output){
// Call to database , returns a promise, like an Ajax call etc :
const response = await axios.get( GetApiHost() + '/api/some_endpoint')
// Return :
return response;
}
and then I would call this function from main function :
async function justTesting() {
const lv_result = await SubFunction(output);
return lv_result + 1;
}
Noting that I returned both main function and sub function to async functions here.
Promises don't "return" values, they pass them to a callback (which you supply with .then()).
It's probably trying to say that you're supposed to do resolve(someObject); inside the promise implementation.
Then in your then code you can reference someObject to do what you want.
I think what the original poster wants is to return an unwrapped value from a promise without actually returning another promise. Unless proven otherwise, I'm afraid this is not possible outside of a then() or async/await context. You always get a promise no matter what.
You need to make use of reference data type like array or object.
function foo(u,n){
let result = [];
const userBrands = new Promise((res, rej)=> {
res(['brand 1', 'brand 3']);
})
userBrands.then((ub)=>{
return new Promise((res, rej) =>{
res([...ub, 'brand 4', 'brand 5']);
})
}).then(response => {
return result.push(...response);
});
return result;
};
foo();
You cannot return value after resolving promise. Instead call another function when promise is resolved:
function justTesting() {
promise.then(function(output) {
// instead of return call another function
afterResolve(output + 1);
});
}
function afterResolve(result) {
// do something with result
}
var test = justTesting();

Categories

Resources