It seems that if the 'resolve' function is not referenced in the function that is used to create a promise, then the promise is undefined. In the code below, ...
var count = 0;
var limit = 3;
//
var thePromise;
function timeout(_count) {
thePromise.resolve(_count);
}
function sendMessage() {
return new Promise(function(resolve, reject) {
if (++count > limit) {
reject({'Limit Exceeded': count});
}
else {
// With this line in place, the return value from this function
// (expected to be a promise) is undefined
setTimeout(timeout.bind(null, count), 1000);
// If the line above is replaced by this, it works as expected
// setTimeout(/*timeout.bind(null, count)*/function (_count) {
// resolve(_count);
// }.bind(null, count), 1000);
}
});
}
function sendAnother(_count) {
console.log('Resolved with count %j', _count);
return sendMessage();
}
function detectError(_error) {
console.log('Rejected with %s', JSON.stringify(_error));
process.exit(1);
}
thePromise = sendMessage();
thePromise = thePromise.then(function (_count) { return sendAnother(_count)}, function(_error) {detectError(_error)});
trying to do the resolve outside of the function that creates the promise, results in:
node-promises.js:6
thePromise.resolve(_count);
^
TypeError: undefined is not a function
at timeout (node-promises.js:6:16)
at Timer.listOnTimeout (timers.js:110:15)
But if line 16 is commented out and lines 18-20 are uncommented, the output is:
Resolved with count 1
.. which is what I expected. What am I missing? This is using nodejs v0.12.2 on Windows 7, if that makes any difference.
It happens because of this line:
thePromise.resolve(_count);
there is no resolve function on that object. resolve comes from the function you have created when instantiating the new promise:
return new Promise(function(resolve, reject) {
By commenting out that line, and using the alternate function, you are calling the correct resolve(), which causes the desired output. One option to fix this could be to pass the resolve function into your timeout call, eg:
function timeout(resolve, _count) {
resolve(_count);
}
Although I am not sure why you would want to do this.
Your title asks why new Promise is returning undefined, when the fact is that it isn't. It is indeed returning a valid promise. It is just that resolve is not a valid function on the promise object.
Related
I am stuck trying to build a recursive function that is already defined as a promise.
I have not been able to apply the recursive pattern on the code below which is looping only once even though loopFor is initialised at 20 what I am missing?
Requirement: receivingMessages must be a promise.
let globalMessageArray = [];
let count = 0;
let loopFor = 20;
function receivingMessages(params, loopFor, globalMessageArray) {
return new Promise((resolve, reject) => {
const command = new ReceiveMessageCommand(params);
client.send(command).then(
(data) => {
if (data && data.Messages && data.Messages.length) {
data.Messages.forEach(msg => {
globalMessageArray.push(msg);
});
};
return resolve(globalMessageArray);
},
(error) => {
return reject(error);
}).then(
(globalMessageArray) => {
count = count + 1;
console.log("Loop Count: " + count); // always returns 1
if (loopFor === 1) {
return resolve(globalMessageArray);
} else {
return resolve(receivingMessages(params, loopFor - 1, globalMessageArray));
};
});
});
};
In the first then callback client.send(cmd).then(data => … you return resolve(globalMessageArray). This effectively short-circuit your loop, because a promise can only resolve once. Later call of resolve has no effect.
client.send(cmd).then((data) => {
…
return globalMessageArray;
}, …
Remove first call to resolve should solve your problem.
You said in comment:
Using async/await would imply to rewrite the whole program
No, your understanding of async/await is wrong. Any async function is automatically a promise returning function, which meets your requirement. Async/await is just syntax sugar on top of promise.
This means you can safely rewrite ONLY receivingMessages function without needing to modify other places that call it.
Although there is nothing wrong with vanilla promise, rewriting to async/await will make your code so much cleaner.
async function receivingMessages(params, loopFor, globalMessageArray) {
const command = new ReceiveMessageCommand(params);
const data = await client.send(command);
if (data && data.Messages && data.Messages.length) {
data.Messages.forEach(msg => {
globalMessageArray.push(msg);
});
}
if (loopFor === 1) {
return globalMessageArray;
} else {
return receivingMessages(params, loopFor - 1, globalMessageArray)
};
};
The issue with your code is that the resolve call in the then callback after the client.send promise resolves is returning the result of calling receivingMessages instead of the receivingMessages promise itself. This causes the recursive loop to only execute once.
To fix this, you can change the resolve call to return the result of calling receivingMessages directly:
return receivingMessages(params, loopFor - 1, globalMessageArray);
This will cause the receivingMessages function to be called in a recursive manner until loopFor reaches 1.
You may also want to consider adding a base case to the function to ensure that it terminates, such as adding a check for loopFor being less than or equal to 0 and returning the globalMessageArray in that case.
This question already has answers here:
Where do the promise callback arguments come from
(3 answers)
When or who does pass resolve and reject functions to JS promises?
(6 answers)
Closed 2 months ago.
I'm trying to understand Promises and their optional arguments.
(I'm assuming that because the arguments are optional, that too few are acceptable, and that too many arguments are also acceptable).
As an example:
let myPromise = new Promise(function(first, second, third) {
let x = 0;
if (x == 0) { //<<true
second();
} else {
third();
}
});
myPromise.then(
function() {
console.log("1");
},
function() {
console.log("2");
}
);
Runs the second function and outputs "2".
let myPromise = new Promise(function(first, second, third) {
let x = 0;
if (x != 0) { //<<false
second();
} else {
third();
}
});
myPromise.then(
function() {
console.log("1");
},
function() {
console.log("2");
}
);
Also runs the second function and outputs "2".
In the first case, is the Promise calling the function by name; And in the second case, calling the function by position?
How exactly does a Promise know which function to call?
The order of arguments matters because the order values are passed in determines which variables they are assigned to.
The callback to new Promise is given two arguments. A function to call to resolve the promise and a function to call to reject it. It doesn't get passed a third argument so third is undefined.
The then method takes two arguments. A function to call if the promise is resolved and a function to call if the promise is rejected.
In your second example, the promise is rejected. This isn't because you called the reject function, but because you attempted to call undefined as if it was a function causing an exception to be thrown.
const promise = new Promise((resolve, reject, third) => {
console.log(typeof resolve);
console.log(typeof reject);
console.log(typeof third);
third();
});
promise.then(
(value) => console.log("Resolved", value),
(error) => console.log("Rejected", error.message)
);
The first argument to the constructor callback is the resolver function - call it, and it'll result in the returned Promise being fulfilled.
The second argument is a function that, if called, will result in the Promise rejecting.
The third (and all subsequent) arguments are undefined. You're free to define them when constructing a Promise, but their values will always be undefined.
In the first snippet, the second argument is called, rejecting the Promise.
In the second snippet, you call the third argument - but the third argument is not a function. A synchronous error thrown inside the Promise constructor results in the Promise rejecting. Check the error.message in the error handler for better understanding:
let myPromise = new Promise(function(first, second, third) {
third();
});
myPromise.then(
function() {
console.log("1");
},
function(x) {
console.log(x.message);
}
);
So it's not that you're free to call whichever positional argument you wish, and the engine will magically understand what you were trying to do - it's that anything that results in an error being thrown will result in the Promise getting rejected, no matter the arguments.
I want to override the Promise constructor and the then method in Promise.
So, whenever someone creates a new Promise object, first my code will be executed and then the original promise constructor will get called.
Similarly, when someone calls .then function of Promise, first my code will get executed and then the callback of then function will get executed.
I tried this
var bind = Function.bind;
var unbind = bind.bind(bind);
function instantiate(constructor, args) {
return new (unbind(constructor, null).apply(null, args));
}
var oldProto = Promise.prototype;
Promise = function() {
console.log("Promise instantiated");
var promise = instantiate(Promise, arguments);
return promise;
};
Promise.prototype = oldProto;
While calling this using
var myFirstPromise = new Promise((resolve, reject) => {
setTimeout(function(){
resolve("Success!"); // Yay! Everything went well!
}, 250);
});
myFirstPromise.then((successMessage) => {
console.log("Yay! " + successMessage);
});
It led to infinite loop with console filled up with Promise instantiated log. I also tried the following:
Promise = function(Promise) {
MyPromise.prototype = Promise.prototype;
function MyPromise(){
console.log("Hello");
var promise = Function.prototype.bind.apply(MyPromise, arguments);
console.log(promise);
return promise;
}
}(Promise);
But, I am not sure whether the constructor overriden is the correct way to do it and how to define the then function for Promise.
I am not really sure I understand the difference between these two common scenarios.
Say we have this:
user.save().then(function(val){
anotherPromise1(val);
}).then(function(val){
anotherPromise2(val);
}).catch(function(err){
});
versus:
user.save().then(function(val){
return anotherPromise1(val);
}).then(function(val){
return anotherPromise2(val);
}).catch(function(err){
});
I know it makes a difference but how exactly?
If you don't return a value from the then callback, you're effectively returning undefined. The next then callback will run immediately, and see undefined as the resolution value.
If you return a promise from the then callback, the second then callback waits on that promise (indirectly, but that doesn't really matter), and when that promise is resolved, gets the resolution value from that promise.
(This is covered by the then specification in the Promises/A+ spec, but slightly by omission — it doesn't explicitly mention what should happen if onFulfilled doesn't return anything, but in JavaScript, calling a function always gives you a resulting value; if the function doesn't explicitly return something, undefined is the result of calling it. JavaScript doesn't have the concept of void methods a'la C/C#/C++/Java.)
You can see it in this script live copy on Babel's REPL:
let start = Date.now();
function elapsed() {
let rv = String(Date.now() - start);
while (rv.length < 4) {
rv = "0" + rv;
}
return rv;
}
function anotherPromise(type, val) {
console.log(`${elapsed()}: anotherPromise[${type}] got ${val}`);
return new Promise(resolve => {
setTimeout(() => { resolve(val * 2); }, 1000);
});
}
function anotherPromise2(type, val) {
console.log(`${elapsed()}: anotherPromise2[${type}] got ${val}`);
return new Promise(resolve => {
setTimeout(() => { resolve(val * 3); }, 10);
});
}
let user = {
save: () => {
return new Promise(resolve => {
setTimeout(() => {
resolve(42);
}, 10);
});
}
}
// Without return
user.save().then(function(val){
anotherPromise("without", val);
}).then(function(val){
anotherPromise2("without", val);
}).then(function() {
console.log(`${elapsed()}: All done`);
}).catch(function(err){
});
user.save().then(function(val){
return anotherPromise("with", val);
}).then(function(val){
return anotherPromise2("with", val);
}).then(function() {
console.log(`${elapsed()}: All done`);
}).catch(function(err){
});
The output is (for example):
0015: anotherPromise[without] got 42
0017: anotherPromise2[without] got undefined
0018: All done
0020: anotherPromise[with] got 42
1021: anotherPromise2[with] got 84
1032: All done
Note the differences between without a return and with a return:
Without, anotherPromise2 was called immediately (as we can see from the elapsed time values) and received undefined.
With, anotherPromise2 waited for anotherPromise's resolution to occur, and then received 84 (anotherPromise's resolution value)
The difference is the timing in this matter.
In example 1, the save promise is fullfilled and the anotherPromise1 will be invoked and because there is no promise returned, the anotherPromise2will be invoked immediately.
If you return the promise of the anotherPromise1 function, the invokation of anotherPromise will happen, after anotherPromise1 was resolved.
So example 1: anotherPromise1 and anotherPromise2 will be shot simultaneous
While example 2: anotherPromise2 will wait for anotherPromise1 to be resolved
I'm new to promises and trying to wrap my head around something that should be simple. Maybe someone can hit me in the head with it instead!
I've got these two functions:
//an arbitrary method that runs on delay to mimic an async process
method1 = function( _value, _callback ){
setTimeout(function(){
console.log('dependency1_resolved');
_callback.apply(this, [{valIs:_value}]);
}.bind(this), (Math.random() * 1000));
};
//something that can simple return the object
function returnVal(x){
console.log(x); //this logs 'Object {valIs: 4}'
return x;
}
due to it's async nature, I'd like to run this function in a promise to be used later (maybe even chain later) in my code.
here is my promise:
var promise = new Promise(
function(resolve, reject) {
var x = method1(4, returnVal);
resolve(x);
}
);
promise.then(function(val) {
console.log(val); // undefined
return val;
});
console.log(promise); //Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: undefined}
Does this have anything to do with the .apply method in the first function? What am I missing? Can someone please slap me?
Your returnVal callback doesn't actually do anything.
Instead, you need to actually pass a callback that accepts the value:
var promise = new Promise(
function(resolve, reject) {
method1(4, function(x) { resolve(x); });
}
);
You can also just pass resolve itself as the callback:
var promise = new Promise(
function(resolve, reject) {
method1(4, resolve);
}
);
Your method1 does return nothing, that's why x is undefined. That the returnVal callback does return something is insignificant, its return value is simply ignored by method1.
You will need to call resolve as the callback to make your code work:
new Promise(
function(resolve, reject) {
var x = method1(4, resolve);
}
).then(function(val) {
console.log(val); // undefined
return val;
});
See also How do I return the response from an asynchronous call?