Executing promises in a sequence - javascript

An example from this page. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
var p1 = new Promise(function(resolve, reject){
console.log('p1');
setTimeout(resolve, 5000, "one");
});
var p2 = new Promise(function(resolve, reject){
console.log('p2');
setTimeout(resolve, 3000, "two");
});
var p3 = new Promise(function(resolve, reject){
console.log('p3');
setTimeout(resolve, 2000, "three");
});
var p4 = new Promise(function(resolve, reject){
console.log('p4');
setTimeout(resolve, 1000, "four");
});
var p5 = new Promise(function(resolve, reject){
console.log('p5');
setTimeout(resolve, 4000, "five");
});
Promise.all([p1, p2, p3, p4, p5]).then(function(value) {
console.log(value);
}, function(reason) {
console.log(reason)
});
Output
p1, p2, p3, p4, p5
All p1-p5 are executed at once but let's say if I want to sequence it. Once p1 resolves, then p2 should be called, and then p3.
How can I sequence/chain (instead of parallel) the promises instead of an iteration through all at once.
It's creating callback hell if I do a manual approach on waiting for each promise. Please advise.

Firstly, promises may or may not start executing immediately after creation.
(Note: by immediately, it is relative to the execution loop.)
In your above code, p1 to p5 starts counting down as soon as you leave the current execution loop.
To ensure the promises does not get executed before you want them to, you would have to wrap them in a promise generating function.
var p1 = function(){
return new Promise(function(resolve, reject){
console.log('p1');
setTimeout(resolve, 5000, "one");
});
};
var p2 = function(){
return new Promise(function(resolve, reject){
console.log('p2');
setTimeout(resolve, 3000, "two");
});
};
var p3 = function(){
return new Promise(function(resolve, reject){
console.log('p3');
setTimeout(resolve, 2000, "three");
});
};
var p4 = function(){
return new Promise(function(resolve, reject){
console.log('p4');
setTimeout(resolve, 1000, "four");
});
};
var p5 = function(){
return new Promise(function(resolve, reject){
console.log('p5');
setTimeout(resolve, 4000, "five");
});
};
For the above case, if you already know the number of promises you have, you can simply chain the promises together:
p1().then(p2).then(p3).then(p4).then(p5).then(function(){
// Hurray! All done!
console.log("All done :)");
});
However, if you have a variable amount of promises to chain in sequence, you would have to make use of loops (see #PitaJ's answer) or Array.reduce.
var arrayOfPromiseGeneratingFunctions = [p1, p2, p3, p4, p5]; // Can be of any size.
// Take the first promise-generating function as chain initializer
var initialFn = arrayOfPromiseGeneratingFunctions.shift();
// Here we're effectively doing promise chaining like the simple solution above
var finalPromise = arrayOfPromiseGeneratingFunctions.reduce(function(previousPromise, fn){
return previousPromise.then(fn)
}, initialFn());
finalPromise.then(function(){
// Last promise called
});
This solution is suitable for an arbitrary number of sequentially executed promises, so as long as you wrap the promises with a function.
Some other catches about this implementation:
1. In the example we wrap p1 to p5 into a function, so that they don't get executed in any way before you want it to.
2. You can pass results promise results from one to another, by adding the parameter in the promise-generating function. Since the first parameter would effectively be the resolve result of the last promise.
Further reading: https://github.com/kriskowal/q#sequences

Promise is executed immediately on creation. You have to use then to chain actions.
new Promise(function(resolve, reject){
console.log('p1');
setTimeout(resolve, 5000, "one");
}).then(() => {
console.log('p2');
setTimeout(resolve, 3000, "two");
}).then(() => {
console.log('p3');
setTimeout(resolve, 2000, "three");
}).then(() => {
console.log('p4');
setTimeout(resolve, 1000, "four");
}).then(() => {
console.log('p5');
setTimeout(resolve, 4000, "five");
});

You can do something like this:
function sequential(promiseArr) {
var p = Promise.resolve(), i = 0, l = promiseArr.length;
for (; i < l; i += 1) {
p = p.then(promiseArr[i]);
}
return p;
}
Edit: Fixed it. Would have failed because p wasn't initialized to start.

Let me rephrase your problem.
You have a function which return a promise. You need to call this function again and again with different arguments only when the previous promise is resolved.
Lets imagine following is the function.
function getPromise(arg) {
return new Promise(function(resolve){
setTimeout(resolve, Math.random() * 10000, [arg]);
})
};
Here is your argument list
var promiseSetup = ['apple', 'orange', 'grapes'];
You can have objects which contain functions to be executed too instead of simple demo params here.
Now I'm going to put down the logic which will execute above promise functions repeatedly with each of the arguments. This will be done in a sequence.
function promiseWaterfall(args, promFunc, idx) {
if (idx >= args.length)
return;
console.log('executing ' + args[idx]);
promFunc(args[idx]).then(function(){
promiseWaterfall(args, promFunc, idx + 1)
});
}
Explanation
The above function is recursive. It will call itself with an advanced index value only when the previous promise it obtained is resolved.
Also note that you can execute a function every time a promise is resolved. You can make the "apple" an apple object like this
[{arg: "apple", func: executeApple}]
Then execute this function where we log the console message.

Related

Promises - How to make asynchronous code execute synchronous without async / await?

var p1 = new Promise(function(resolve, reject) {
setTimeout(() => resolve("first"), 5000);
});
var p2 = new Promise(function(resolve, reject) {
setTimeout(() => resolve("second"), 2000);
});
var p3 = new Promise(function(resolve, reject) {
setTimeout(() => resolve("third"), 1000);
});
console.log("last to print");
p1.then(()=>p2).then(()=>p3).then(()=> console.log("last to be printed"))
As I was reading about promises, I know that I can print promises synchronous (in this case print: first, second, third, last to print) when I use async /await. Now I have also been reading that the same thing can be achieved using .then chaining and async/await is nothing 'special'. When I try to chain my promises, however, nothing happens except for the console.log of "last to be printed". Any insight would be great! Thanks!!
Edit to question:
var p1 = new Promise(function (resolve, reject) {
setTimeout(() => console.log("first"), 5000);
resolve("first resolved")
});
var p2 = new Promise(function (resolve, reject) {
setTimeout(() => console.log("second"), 2000);
resolve("second resolved")
});
var p3 = new Promise(function (resolve, reject) {
setTimeout(() => console.log("third"), 0);
resolve("third resolved")
});
console.log("starting");
p1.then((val) => {
console.log("(1)", val)
return p2
}).then((val) => {
console.log("(2)", val)
return p3
}).then((val) => {
console.log("(3)", val)
})
Loggs:
starting
(1) first resolved
(2) second resolved
(3) third resolved
third
second
first
1: if executor function passed to new Promise is executed immediately, before the new promise is returned, then why are here promises resolved ()synchronously) first and after the setTimeouts (asynchronously) gets executed?
Return value vs. resolve promise:
var sync = function () {
return new Promise(function(resolve, reject){
setTimeout(()=> {
console.log("start")
resolve("hello") //--works
// return "hello" //--> doesnt do anything
}, 3000);
})
}
sync().then((val)=> console.log("val", val))
The executor function you pass to new Promise is executed immediately, before the new promise is returned. So when you do:
var p1 = new Promise(function(resolve, reject) {
setTimeout(() => resolve("first"), 5000);
});
...by the time the promise is assigned to p1, the setTimeout has already been called and scheduled the callback for five seconds later. That callback happens whether you listen for the resolution of the promise or not, and it happens whether you listen for resolution via the await keyword or the then method.
So your code starts three setTimeouts immediately, and then starts waiting for the first promise's resolution, and only then waiting for the second promise's resolution (it'll already be resolved, so that's almost immediate), and then waiting for the third (same again).
To have your code execute those setTimeout calls only sequentially when the previous timeout has completed, you have to not create the new promise until the previous promise resolves (using shorter timeouts to avoid lots of waiting):
console.log("starting");
new Promise(function(resolve, reject) {
setTimeout(() => resolve("first"), 1000);
})
.then(result => {
console.log("(1) got " + result);
return new Promise(function(resolve, reject) {
setTimeout(() => resolve("second"), 500);
});
})
.then(result => {
console.log("(2) got " + result);
return new Promise(function(resolve, reject) {
setTimeout(() => resolve("third"), 100);
});
})
.then(result => {
console.log("(3) got " + result);
console.log("last to print");
});
Remember that a promise doesn't do anything, and doesn't change the nature of the code in the promise executor. All a promise does is provide a means of observing the result of something (with really handy combinable semantics).
Let's factor out the common parts of those three promises into a function:
function delay(ms, ...args) {
return new Promise(resolve => {
setTimeout(resolve, ms, ...args);
});
}
Then the code becomes a bit clearer:
function delay(ms, ...args) {
return new Promise(resolve => {
setTimeout(resolve, ms, ...args);
});
}
console.log("starting");
delay(1000, "first")
.then(result => {
console.log("(1) got " + result);
return delay(500, "second");
})
.then(result => {
console.log("(2) got " + result);
return delay(100, "third");
})
.then(result => {
console.log("(3) got " + result);
console.log("last to print");
});
Now, let's put that in an async function and use await:
function delay(ms, ...args) {
return new Promise(resolve => {
setTimeout(resolve, ms, ...args);
});
}
(async() => {
console.log("starting");
console.log("(1) got " + await delay(1000, "first"));
console.log("(2) got " + await delay(500, "second"));
console.log("(3) got " + await delay(100, "third"));
console.log("last to print");
})();
Promises make that syntax possible, by standardizing how we observe asynchronous processes.
Re your edit:
1: if executor function passed to new Promise is executed immediately, before the new promise is returned, then why are here promises resolved ()synchronously) first and after the setTimeouts (asynchronously) gets executed?
There are two parts to that question:
A) "...why are here promises resolved ()synchronously) first..."
B) "...why are here promises resolved...after the setTimeouts (asynchronously) gets executed"
The answer to (A) is: Although you resolve them synchronously, then always calls its callback asynchronously. It's one of the guarantees promises provide. You're resolving p1 (in that edit) before the executor function returns. But the way you're observing the resolutions ensures that you observe the resolutions in order, because you don't start observing p2 until p1 has resolved, and then you don't start observing p3 until p2 is resolved.
The answer to (B) is: They don't, you're resolving them synchronously, and then observing those resolutions asynchronously, and since they're already resolved that happens very quickly; later, the timer callbacks run. Let's look at how you create p1 in that edit:
var p1 = new Promise(function (resolve, reject) {
setTimeout(() => console.log("first"), 5000);
resolve("first resolved")
});
What happens there is:
new Promise gets called
It calls the executor function
The executor function calls setTimeout to schedule a callback
You immediately resolve the promise with "first resolved"
new Promise returns and the resolved promise is assigned to p1
Later, the timeout occurs and you output "first" to the console
Then later you do:
p1.then((val) => {
console.log("(1)", val)
return p2
})
// ...
Since then always calls its callback asynchronously, that happens asynchronously — but very soon, because the promise is already resolved.
So when you run that code, you see all three promises resolve before the first setTimeout callback occurs — because the promises aren't waiting for the setTimeout callback to occur.
You may be wondering why you see your final then callback run before you see "third" in the console, since both the promise resolutions and the console.log("third") are happening asynchronously but very soon (since it's a setTimeout(..., 0) and the promises are all pre-resolved): The answer is that promise resolutions are microtasks and setTimeout calls are macrotasks (or just "tasks"). All of the microtasks a task schedules are run as soon as that task finishes (and any microtasks that they schedule are then executed as well), before the next task is taken from the task queue. So the task running your script does this:
Schedules a task for the setTimeout callback
Schedules a microtask to call p1's then callback
When the task ends, its microtasks are processed:
The first then handler is run, scheduling a microtask to run the second then handler
The second then handler runs and schedules a micro task to call the third then handler
Etc. until all the then handlers have run
The next task is picked up from the task queue. It's probably the setTimeout callback for p3, so it gets run and "third" appears in the console
Return value vs. resolve promise:
The part you've put in the question doesn't make sense to me, but your comment on this does:
I read that returning a value or resolving a promise is same...
What you've probably read is that returning a value from then or catch is the same as returning a resolved promise from then or catch. That's because then and catch create and return new promises when they're called, and if their callbacks return a simple (non-promise) value, they resolve the promise they create with that value; if the callback returns a promise, they resolve or reject the promise they created based on whether that promise resolves or rejects.
So for instance:
.then(() => {
return 42;
})
and
.then(() => {
return new Promise(resolve => resolve(42));
})
have the same end result (but the second one is less efficient).
Within a then or catch callback:
Returning a non-promise resolves the promise then/catch created with that value
Throwing an error (throw ...) rejects that promise with the value you throw
Returning a promise makes then/catch's promise resolve or reject based on the promise the callback returns
You cannot make asynchronous code execute synchronously.
Even async / await are just syntax that gives you a synchronous-style control flow inside a promise.
When I try to chain my promises, however, nothing happens except for the console.log of "last to be printed". Any insight would be great!
The other functions don't generate any output. That has nothing to do with them being in promises.
You start three timers (all at the same time), then log 'last to print', then chain some promises so that 'last to be printed' will print when all three promises resolve (5 seconds after you start them all going).
If you want the timers to run sequentially, then you have to initiate them only when the previous one has finished, and if you want to see what they resolve with then you have to write code that actually looks at that.
function p1() {
return new Promise(function(resolve, reject) {
setTimeout(() => resolve("first"), 5000);
});
}
function p2() {
return new Promise(function(resolve, reject) {
setTimeout(() => resolve("second"), 2000);
});
}
function p3() {
return new Promise(function(resolve, reject) {
setTimeout(() => resolve("third"), 1000);
});
}
function log(value) {
console.log("Previous promise resolved with " + value);
}
p1()
.then(log)
.then(p2)
.then(log)
.then(p3)
.then(log)
.then(() => console.log("last to be printed"));
Async/await is, arguably, neater:
function p1() {
return new Promise(function(resolve, reject) {
setTimeout(() => resolve("first"), 5000);
});
}
function p2() {
return new Promise(function(resolve, reject) {
setTimeout(() => resolve("second"), 2000);
});
}
function p3() {
return new Promise(function(resolve, reject) {
setTimeout(() => resolve("third"), 1000);
});
}
function log(value) {
console.log("Previous promise resolved with " + value);
}
(async function() {
log(await p1());
log(await p2());
log(await p3());
console.log("last to be printed");
}());
If you need to call an await but the function that contains that await doesn't have to be async, because you need, for example, a "number" and not a "Promise number ", you can do de next:
var ex: number = new Number(async resolve => {
var f = await funcionExample();
resolve(f);
}).valueOf();

Javascript Promise push value into array (only from function or outside?)

I have some promises and a Promise.all:
array = [];
var one = new Promise(function(resolve, reject) {
// Do stuff
setTimeout(function() {
resolve('One Done');
array.push('one');
}, 5000);
});
var two = new Promise(function(resolve, reject) {
// Do Stuff
resolve('Two Done');
array.push('two');
});
Promise.all(array).then(values => {
console.log(values);
});
We know this doesn't work because array.push needs to be outside.
I currently have a few functions which I need to have called by promises so that finally I can have it in Promise.all.
Would it be advisable to call the function from inside the promise like this:
function dosomething() {
// does something
array.push('something');
}
var mypromise = new Promise(function(resolve, reject) {
dosomething();
resolve('Did something');
});
Or is there a more advisable way to do this?
Promise.all waits for an array of Promises. In your example, you are always pushing string types into an array. This obviously won't work. In your first example, you want to push the promises themselves:
array = [];
var one = new Promise(function(resolve, reject) {
// Do stuff
setTimeout(function() {
resolve('One Done');
}, 5000);
});
array.push(one);
var two = new Promise(function(resolve, reject) {
// Do Stuff
resolve('Two Done');
});
array.push(two);
Promise.all(array).then(values => {
console.log(values);
});
As long as the array contains Promise objects, Promise.all will work as expected.
Promise.All expects an array of promises, and will wait until all promises are fullfilled, providing you with the results of each Promise or a catch if any of them fails.
You can resolve them with any type of object if you are willing to resolve it with more than just a string, and you can use the results afterwards in any way you want, so you could avoid messing with the array inside from the promise and instead resolve the "work item" as a unit and use all required results after the async evaluation.
This will also ( i think ) make the code cleaner and more managable.
You could instead try to do this:
var valuesArray=[];
var prom1 = new Promise(function(resolve, reject) {
// Do stuff
setTimeout(function() {
resolve({ msg: 'One Done', data : 'one'});
// array.push('one');
}, 5000);
});
var prom2 = new Promise(function(resolve, reject) {
// Do Stuff
resolve({ msg: 'Two Done', data : 'two'});
// array.push('two');
});
var promisesArray= [prom1,prom2];
Promise.all(promisesArray).then(values => {
// do stuff with values here
console.log(values[0].msg);
console.log(values[1].msg);
valuesArray.push(values[0].data);
valuesArray.push(values[0].data);
});
I think it would be clearest if you called Promise.all with the array of Promises, with each Promise resolving to the desired value, no outer array nor push at all:
var one = new Promise(function(resolve, reject) {
// Do stuff
setTimeout(function() {
console.log('One Done')
resolve('one');
}, 1000);
});
var two = new Promise(function(resolve, reject) {
// Do Stuff
console.log('Two Done');
resolve('two');
});
Promise.all([one, two]).then(arr => {
console.log(arr);
});
If you need both values (the 'One Done' and the 'one'), you can resolve the initial promises with an array with both values, doing whatever you need to with the 'One Done', and then resolving with the 'one' to be chained with array created by Promise.all:
const logAndReturn = ([logStr, finalResolveStr]) => {
console.log(logStr);
return finalResolveStr;
}
var one = new Promise(function(resolve, reject) {
// Do stuff
setTimeout(function() {
resolve(['One Done', 'one']);
}, 1000);
});
var two = new Promise(function(resolve, reject) {
// Do Stuff
resolve(['Two Done', 'two']);
});
Promise.all([
one.then(logAndReturn),
two.then(logAndReturn),
]).then(arr => {
console.log(arr);
});

slowness in promise chain

my codes transfers huge number of files from one cloud storage to another cloud storage (same region). The workflow is downloading the source file stream, then uploading the stream to the target storage.
If running them in a non-promise loop, the transferring is fast(say, 100M/s), but will hit the memory limit. Finally the server crashes.
if in a promise chain, i.e. run the next job after the last job completes, the crash problem is solved, but the transferring speed is very slow (say 10M/s).
My question: why the promise would affect the downloading & uploading speed? or anything I missed?
code snippet:
transferArray.forEach(function (eachTransfer) {
queue = queue.then(function(result){
// put result somewhere
return eachFileTransfer(jobId,userid,eachTransfer);
});
});
queue.then(function(){
console.log('done');
});
I am thinking to use PromisePool with concurrences, but not sure how much the speed would be improved, and the reasonable number of concurrences I should set. the ref post:
Execute promises concurrently with a buffer pool size in Javascript
Cause i guess with your loop you run a lot of requests in parallel, wich will be faster (but will also exceed all kind of limits). Therefore just as you said, use multiple promise chains:
const inParallel = 10;
const promises = (new Array(inParallel)).fill(Promise.resolve());
for(const [index, transfer] of transferArray.entries())
promises[index % inParallel] = promises[index % inParallel].then(() => eachFileTransfer(jobId,userid,eachTransfer));
finally, I made it working by PromisePool. The code snippet below is based on the other post: Execute promises concurrently with a buffer pool size in Javascript
Since my code is relatively complex than this post, thought it might be helpful for some others:
var PromisePool = require('es6-promise-pool');
//single promises
function p1(){
return new Promise(function(resolve, reject) {
console.log('p1');
setTimeout(resolve, 2000, 'foo');
});
}
function p2(){
return new Promise(function(resolve, reject) {
console.log('p2');
setTimeout(resolve, 2000, 'foo');
});
}
function p3(){
return new Promise(function(resolve, reject) {
console.log('p3');
setTimeout(resolve, 2000, 'foo');
});
}
var tasks=[];
var loopIndex = 0;
[1,2,3,4,5,6,7,8].forEach(function(v,i){
console.log(v,i);
//build promise chain
var x = (v) => new Promise(function(resolve, reject) {
console.log(v);
p1().then(function(r){
return p2();
})
.then(function(r){
return p3();
})
.then(function(r){
//console.log('embedded chain done');
resolve('embedded chain done');
}).catch(function(e){
reject('embedded chain failed');
});
//setTimeout(resolve, 2000, 'foo');
})
//build one promise task
tasks.push({fun:x,param:i});
if(++loopIndex == 8){
//once the array is done
const promiseProducer = () => {
while(tasks.length) {
console.log('processing ');
const task = tasks.shift();
return task.fun(task.param);
}
return null;
}
// concurrent Promises set to 3
const pool = new PromisePool(promiseProducer, 3);
//start to promise all, yet with concurrent 3 tasks.
const poolPromise = pool.start();
poolPromise.then(() => { console.log('done!'); })
}
});

How to successfully loop in the middle of a promise chain

I'm putting together a promise chain, new to this so apologies. What I want to do is, for any errors in any particular function, I want to wait a second and try again until it succeeds, then continue with the promise chain as per the original plan.
I tried an if statement that called the function again if there was an error message and resolved if there was not, but this would not continue with the promise chain on a success.
I then worked a solution that included a for loop built into the function, as below:
var firstMethod = function() {
var promise = new Promise(function(resolve, reject){
setTimeout(function() {
console.log('first method completed');
resolve();
}, 1000);
});
return promise;
};
var secondMethod = function(someStuff) {
var promise = new Promise(function(resolve, reject){
for(let randomNumber ; randomNumber < .9||randomNumber == null ; )
{
setTimeout(function() {
randomNumber = Math.random();
console.log('the number wasn\'t big enough');
if (randomNumber>.9)
{
console.log("got a number big enough");
resolve();
}
}, 1000)
}
});
return promise;
};
var thirdMethod = function(someStuff) {
var promise = new Promise(function(resolve, reject){
setTimeout(function() {
console.log('third method completed');
resolve();
}, 1000);
});
return promise;
};
firstMethod()
.then(secondMethod)
.then(thirdMethod);
It completes firstMethod and then hangs when I try to run it. If I comment out the setTimeout in the secondMethod it works, but I feel this is not emulating the real case scenario I want to use this for.
Where am I going wrong? Is there a better way to loop mid promise chain until you achieve a particular result, then continue with the promise chain?
You can replace the secondMethod with
var secondMethod = function (someStuff) {
var promise = new Promise(function (resolve, reject) {
let randomNumber;
(function doItUntilGetEnoughBigNumber() {
setTimeout(function () {
randomNumber = Math.random();
if (randomNumber > .9) {
console.log("got a number big enough", randomNumber);
resolve();
} else { // edited: message moved her
console.log('the number wasn\'t big enough', randomNumber);
doItUntilGetEnoughBigNumber();
}
}, 1000)
})()
});
return promise;
};
The reason your code doesn't work, because the condition to stop for loop is in asynchronous, so it will be deferred, so the for loop will go forever.
Update Without using IIFE
var secondMethod = function (someStuff) {
var promise = new Promise(function (resolve, reject) {
let randomNumber;
function doItUntilGetEnoughBigNumber() {
setTimeout(function () {
randomNumber = Math.random();
if (randomNumber > .9) {
console.log("got a number big enough", randomNumber);
resolve();
} else {
console.log('the number wasn\'t big enough', randomNumber);
doItUntilGetEnoughBigNumber();
}
}, 1000)
}
doItUntilGetEnoughBigNumber();
});
return promise;
};
The important thing about async events (e.g. when setTimeout finishes) is that the handler is not called directly, but the event is put into the so called event queue. The javascript engine (the event loop) takes one event after another out of it and executes it, when its done it takes the next one. At first it will execute your for loop and set all the timeouts. Then when its done and one second passed it will start executing the setTimeout handlers. But as your for loop is infinite, it will never reach this step.
The easiest would be to use the async syntax:
const timer = ms => start => new Promise(res => setTimeout(res, ms));
async function loop(){
while(true){
await timer(1000)();
if(Math.random() > 0.9) return;
}
}
timer(1000)()
.then(loop)
.then(timer(1000))
.then(() => console.log("done"));
Alternatively you could use a recursive async function:
async function loop(){
await timer(1000)();
if(Math.random() > 0.9)
return true;
else
return loop();
}

JS ES6 Promise Chaining

I'm trying to learn how to use promises, but am having trouble comprehending the chaining. I assume that with this code, both promises will run. Then when I call test.then() it should know that test has resolved and pass the resolve data to then().
Once that function finishes, it goes onto the next then(), repeating the same process with the test2 promise.
However, I can only get it to print out the first promise results, not the second. Any ideas what is missing here?
var test = new Promise(function(resolve, reject){
resolve('done1');
});
var test2 = new Promise(function(resolve, reject){
resolve('done2');
});
test
.then(function(data) {
console.log(data);
})
.then(test2)
.then(function(data) {
console.log(data);
});
Your first .then call is returning undefined, whereas any subsequent .then is expecting a returned promise. So you'd need to change your code to:
var test = new Promise(function(resolve, reject){
resolve('done1');
});
var test2 = new Promise(function(resolve, reject){
resolve('done2');
});
test
.then(function(data) {
console.log(data);
return test2;
})
.then(resultOfTest2 => doSomething)
.then(function(data) {
console.log(data);
});
You need to return next promise from the then callback:
test.then(function(data) {
console.log(data);
return test2;
}).then(function(data) {
console.log(data);
});
Summary:
The basic concept of promise chaining with promises is that every then / catch method on a fulfilled promise returns another promise. It works in the following manner:
When a promise is resolved the callback passed in the then method is called. The then method wraps the value which is returned in its callback in a resolved promise and returns this resolved promise.
When a promise is rejected the callback passed in the catch method is called. The catch method wraps the value which is returned in its callback in a rejected promise and returns this rejected promise.
Example:
Before fully understanding the concept of chaining multiple then methods it is important to know what exactly the return values of then and catch are. Take the following example:
let prom1 = new Promise((res, rej) => {
res('res');
});
const resolvedProm1 = prom1.then((val) => {return val});
// setTimeout needed for the promise to actually be resolved
setTimeout(() => console.log(resolvedProm1));
let prom2 = new Promise((res, rej) => {
rej('rej');
});
const resolvedProm2 = prom2.catch((err) => {throw err});
// setTimeout needed for the promise to actually be rejected
setTimeout(() => console.log(resolvedProm2));
We can observe the status of the promises in the chrome devtools:
What basically happens is that in a then or catch callback is the following:
Any value returned in a then or catch callback is wrapped in Promise.resolve() and a new resolved promise is returned.
Any error thrown in a then or catch callback is wrapped in Promise.reject() and a new rejected promise is returned.
Because we are getting returned a rejected or resolved promise object we can repeat the cycle and call the then or catch method on it again. For example:
const prom = new Promise((res, rej) => {
if (Math.random() > 0.5) {
res('success');
} else {
rej('error');
}
});
prom.then((val) => {
return val;
}).then((val) => {
return val
}).then((val) => {
console.log(val)
}).catch((err) => {
console.log('err');
})
This calling of then and catch methods which are executed in their respective order is called promise chaining. It is a very useful technique to make working with asynchronous code easier, especially if multiple asynchronous operations need to be performed which are dependend on each others data.
you need to return the other promise(test2) in the first promise (test1) to allow for chaining:
var test = new Promise(function(resolve, reject){
resolve('done1');
});
var test2 = new Promise(function(resolve, reject){
resolve('done2');
});
test
.then(function(data) {
console.log(data);
return test2;
});
You may also want to try -
let test = new Promise(function(resolve, reject){
resolve('done1');
});
let test2 = new Promise(function(resolve, reject){
resolve('done2');
});
try {
let logOne = test();
let logTwo = test2();
console.log(logOne);
console.log(logTwo);
} catch(error) {
console.error(error);
}
In this way, you can also properly handle any promise dependencies. For example if test one relied on test two's data your could -
try {
let logOne = test();
let logTwo = test2(logOne);
console.log(logOne);
console.log(logTwo);
} catch(error) {
console.error(error);
}

Categories