Reputation: 277
I wanted to create an example for my understanding of Promise().then()
.
I've created an operation that takes time and have operations that must be completed synchronously.
The code is below:
// Example: long operation that takes time to execute
var longOperation = function(id) {
var time = 1000 * Math.random();
console.log('[' + id + '] Operation started for: ' + time + 'ms');
setTimeout(function(err) {
console.log('[' + id + '] Completed operation: ' + time + 'ms');
var count = id * 10;
}, 1000 * Math.random());
};
// Create new promise for longOperation
var longOpPromise = function(id) {
return new Promise(function(resolve, reject) {
longOperation(id);
resolve(null);
});
};
// Create sequencing
var runLongOperation = function(callback) {
var count1;
longOpPromise(1).then(function(count) {
count1 = count;
console.log('Count 1: ' + count1);
longOpPromise(2).then(function(count2) {
console.log('Count 2: ' + count2);
callback(null, count1, count2);
});
});
};
// Run
runLongOperation(function(err, count1, count2) {
if (err) console.error(err);
console.log('Count 1 ' + count1 + ' | Count 2: ' + count2);
});
The result of running:
**** Output ****
[1] Operation started for: 626.77225866355ms
[1] Completed operation: 626.77225866355ms
The methods in then()
are not executed, nor is the callback. Maybe count is not being resolved.
If I change it to resolve(null)
, these execute but not in sequence:
**** Output ****
[1] Operation started for: 435.5367429088801ms
Count 1: null // This should come after [1] is completed
[2] Operation started for: 256.17250707000494ms
Count 2: null // This should come after [2] is completed
Count 1 null | Count 2: null // This should come after [2] is completed
[2] Completed operation: 256.17250707000494ms
[1] Completed operation: 435.5367429088801ms
Thanks for your help.
Upvotes: 1
Views: 2189
Reputation: 953
One problem is these two lines:
longOperation(id);
resolve(null);
Because longOperation
is an asynchronous function, resolve(null)
will run BEFORE longOperation
has finished running.
I would combine the two first functions to make sure that the promise does not resolve UNTIL the callback in the setTimeout
has run:
var longOpPromise = function(id) {
var time = 1000 * Math.random();
console.log('[' + id + '] Operation started for: ' + time + 'ms');
return new Promise(function(resolve, reject) {
setTimeout(function(err) {
console.log('[' + id + '] Completed operation: ' + time + 'ms');
var count = id * 10;
resolve() // Now the promise won't resolve until here.
}, 1000 * Math.random());
})
};
I would also avoid mixing callbacks and promises like you are doing - except for inbuilt functions like setTimeout
, if you are using promises then you should be able to avoid using callbacks.
Upvotes: 1
Reputation: 943213
You have to call resolve
when the asynchronous operation is complete.
With this code:
longOperation(id); resolve(null);
You are starting the asynchronous operation and then immediately resolving the promise.
If you want to pass the value of count
to your then
function, then you need to pass it when you call resolve()
. At the moment you are passing null
.
This version of your code modifies it to pass resolve
as a callback and only call it at the right time.
// Example: long operation that takes time to execute
var longOperation = function(id, resolve) {
var time = 1000 * Math.random();
console.log('[' + id + '] Operation started for: ' + time + 'ms');
setTimeout(function(err) {
console.log('[' + id + '] Completed operation: ' + time + 'ms');
var count = id * 10;
resolve(count);
}, 1000 * Math.random());
};
// Create new promise for longOperation
var longOpPromise = function(id) {
return new Promise(function(resolve, reject) {
longOperation(id, resolve);
});
};
// Create sequencing
var runLongOperation = function(callback) {
var count1;
longOpPromise(1).then(function(count) {
count1 = count;
console.log('Count 1: ' + count1);
longOpPromise(2).then(function(count2) {
console.log('Count 2: ' + count2);
callback(null, count1, count2);
});
});
};
// Run
runLongOperation(function(err, count1, count2) {
if (err) console.error(err);
console.log('Count 1 ' + count1 + ' | Count 2: ' + count2);
});
Upvotes: 2
Reputation: 67296
I think the main issue here is that your async action (setTimeout
) is not involved with your promise chain.
The resolve(null)
after longOperation(id)
will immediately return null and not wait for the longOperation
function to finish its timeout interval.
Something like this will work:
// Example: long operation that takes time to execute
var longOperation = function(id) {
var time = 1000 * Math.random();
console.log('[' + id + '] Operation started for: ' + time + 'ms');
return new Promise(function(resolve) {
setTimeout(function(err) {
console.log('[' + id + '] Completed operation: ' + time + 'ms');
var count = id * 10;
resolve(count);
}, time);
});
};
// Create new promise for longOperation
var longOpPromise = function(id) {
return longOperation(id);
};
I moved the new Promise
inside of the longOperation
and resolve only when the setTimeout
callback is handled.
Upvotes: 1