"use strict";
let promiseCount = 0;
function testPromise() {
const thisPromiseCount = ++promiseCount;
const log = document.getElementById("log");
// begin
log.insertAdjacentHTML("beforeend", `${thisPromiseCount}) Started<br>`);
// We make a new promise: we promise a numeric count of this promise,
// starting from 1 (after waiting 3s)
const p1 = new Promise((resolve, reject) => {
// The executor function is called with the ability
// to resolve or reject the promise
log.insertAdjacentHTML(
"beforeend",
`${thisPromiseCount}) Promise constructor<br>`
);
// This is only an example to create asynchronism
setTimeout(() => {
// 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((val) => {
// Log the fulfillment value
log.insertAdjacentHTML("beforeend", `${val}) Promise fulfilled<br>`);
}).catch((reason) => {
// Log the rejection reason
console.log(`Handle rejected promise (${reason}) here.`);
});
// end
log.insertAdjacentHTML("beforeend", `${thisPromiseCount}) Promise made<br>`);
}
const btn = document.getElementById("make-promise");
btn.addEventListener("click", testPromise);
<button id="make-promise">Make a promise!</button>
<div id="log"></div>
with refer to promises how do i manually generate a rejected promise or under what circumstances will this code run rejections,please provide some practical concepts so that I can see following error message, please refer in snippet: console.log(Handle rejected promise (${reason}) here.);
Try testing promise rejection by generating rejected promises in the timeout code run within the promise executor function - meaning in the function passed to the global Promise constructor as its argument.
A simple approach might be to reject odd numbered promises while resolving even numbered promises with a settled value. The code below does this if you need an example. It also logs promise rejection in HTML.
"use strict";
let promiseCount = 0;
function testPromise() {
const thisPromiseCount = ++promiseCount;
const log = document.getElementById("log");
// begin
log.insertAdjacentHTML("beforeend", `${thisPromiseCount}) Started<br>`);
// We make a new promise: we promise a numeric count of this promise,
// starting from 1 (after waiting 3s)
const p1 = new Promise((resolve, reject) => {
// The executor function is called with the ability
// to resolve or reject the promise
log.insertAdjacentHTML(
"beforeend",
`${thisPromiseCount}) Promise constructor<br>`
);
// This is only an example to create asynchronism
setTimeout(() => {
// We fulfill the promise on odd calls, reject on even calls
(thisPromiseCount % 2 ? reject : 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((val) => {
// Log the fulfillment value
log.insertAdjacentHTML("beforeend", `${val}) Promise fulfilled<br>`);
}).catch((reason) => {
// Log the rejection reason
console.log(`Handle rejected promise (${reason}) here.`);
log.insertAdjacentHTML("beforeend", `${thisPromiseCount}) Promise rejected<br>`)
});
// end
log.insertAdjacentHTML("beforeend", `${thisPromiseCount}) Promise made<br>`);
}
const btn = document.getElementById("make-promise");
btn.addEventListener("click", testPromise);
<button type="button" id="make-promise">#make-promise</button>
<div id="log"></div>
Related
I've been learning a bit about promises and I came across this example but can't quite understand how it's working. Would someone be able to help break this down into steps so I can understand please, I'm mostly thrown by the cancel parameter and how it's being used. I've tried running the code in console too but I'm still confused. Thanks.
const wait = (
time,
cancel = Promise.reject()
) => new Promise((resolve, reject) => {
const timer = setTimeout(resolve, time);
const noop = () => {};
cancel.then(() => {
clearTimeout(timer);
reject(new Error('Cancelled'));
}, noop);
});
const shouldCancel = Promise.resolve(); // Yes, cancel
// const shouldCancel = Promise.reject(); // No cancel
wait(2000, shouldCancel).then(
() => console.log('Hello!'),
(e) => console.log(e) // [Error: Cancelled]
);
To begin with, Promise.resolve() returns a Promise object that is resolved. Similarly, Promise.reject() returns a rejected Promise object.
The cancel variable holds a rejected or resolved Promise object (a rejected Promise by default).
In case the Promise object within cancel is resolved, it will immediately clear out the timer set in the timer variable and reject it's parent Promise. You can see this in the comment on this line:
const shouldCancel = Promise.resolve(); // Yes, cancel
In case the Promise object within cancel is rejected, it will not clear out the timer, since it won't get to run the lines of code where the timer is cleared out and will instead run the noop function which is an empty no operations funciton. Thus it will let the timer follow it's course and finally resolve it's parent Promise. You can see this in the comment on this line:
// const shouldCancel = Promise.reject(); // No cancel
So the timer will follow it's natural course if shouldCancel = Promise.reject() and return a resolved Promise. If shouldCancel = Promise.resolve(), the timer will get cancelled, and the Promise will be rejected.
in one of youtube tutorial videos about promises I found following code:
let cleanRoom = function() {
return new Promise((resolve, reject) => {
resolve();
});
};
let removeGarbage = function() {
return new Promise((resolve, reject) => {
resolve();
});
};
let winIcecream = function() {
return new Promise((resolve, reject) => {
resolve();
});
};
cleanRoom().then(function(){
return removeGarbage();
}).then(function() {
return winIcecream();
}).then(function() {
console.log('finished');
})
Why the promises aren't chained like that the every .then word is after the previous promise? I mean, why for example .then is not immediately after removeGarbage() but it is after the cleanRoom().then(), how is it happening that the winIcecream() will run after resolving the removeGarbage promise?
Also do I need to type return declaring every promise like in the code above? If yes, why do I need to do so?
Your initial questions may be answered by rewriting things to variable assignments.
I'm using arrow function syntax to implicitly return the new expression here; if you're using regular functions, then yes, you do have to return the new chained promise if you want to run them in sequence.
const roomCleanedPromise = cleanRoom();
const roomCleanedAndGarbageTakenOutPromise = roomCleanedPromise.then(() => removeGarbage());
const roomCleanedAndGarbageTakenOutAndIcecreamWonPromise = roomCleanedAndGarbageTakenOutPromise.then(() => winIcecream());
const finishedPromise = roomCleanedAndGarbageTakenOutAndIcecreamWonPromise.then(() => console.log('finished'));
However things are easier written using the more modern async/await syntax - the YouTube tutorial you mention is a little outdated, perhaps.
async function cleanRoom() {
console.log('Cleaning room.');
// this could do other async things or just take a while
return {room: 'clean'}; // just to demonstrate a return value
}
async function removeGarbage() {
console.log('Removing garbage.');
// this could do other async things or just take a while
return {garbage: 'removed'};
}
// third function elided for brevity
async function doAllTheThings() {
const roomStatus = await cleanRoom();
const garbageStatus = await removeGarbage();
console.log('finished');
}
The purpose of using a fulfillment handler (the functions passed to then in your example) is to wait for the promise to be fulfilled and then, at that point, do something else.
The goal of that code (apparently) is to wait until the cleanRoom promise is fulfilled, then start the removeGarbage process, and then when that is fulfilled, start the winIcecream process. It's also worth noting that if cleanRoom's promise was rejected instead of being fulfilled, removeGarbage wouldn't happen at all, because it's in a fulfillment handler, not a rejection handler.
If you did this instead:
cleanRoom().then(function() { /*...*/ });
removeGarbage().then(function() { /*...*/ });
winIcecream().then(function() { /*...*/ });
...all three processes would be started immediately and run in parallel (to the extent whatever async process they're modelling can run in parallel with other JavaScript code). There'd be no coordination between them at all.
...how is it happening that the winIcecream() will run after resolving the removeGarbage promise...
then, catch, and finally create and return new promises. Those promises are fulfilled or rejected based on what happens to the promise they were called on and what happens in or is returned by their handler. So for example:
doThis()
.then(function() { return doThat(); })
.then(function() { console.log("done"); });
Let's call the promise from doThis() "Promise A". Calling then on it creates a new promise ("Promise B"), that will either be rejected (if Promise A is rejected) or will call its handler if Promise A is fulfilled. Promise B is resolved to whatever that handler returns. In the code above, suppose Promise A is fulfilled and doThat() returns a promise ("Promise C"). Now, Promise B is resolved to Promise C — whatever happens to Promise C is what will happen to Promise B. If Promise C is fulfilled, Promise B is fulfilled, and the second handler with the console.log is called.
The MDN article on using promises may be helpful.
Your suggestion / thinking I mean, why for example .then is not immediately after removeGarbage() but it is after the cleanRoom().then() is wrong.
Each promise ( .then ) is not execute immediately.
You can take a look at your example ( little edited by me )
const cleanRoom = () => new Promise((resolve, reject) => {
resolve();
});
const removeGarbage = () => new Promise((resolve, reject) => {
resolve();
});
const winIcecream = () => new Promise((resolve, reject) => {
resolve();
})
cleanRoom().then(function(){
console.log('second');
return removeGarbage();
}).then(function() {
return winIcecream();
}).then(function() {
console.log('finished');
})
console.log('first');
You should read more how the event loop works.
Why does calling the second function .then(notPromise) still pass the argument to the third function .then(promiseC) even though notPromise() is just a regular function?
I thought only promises can be used with .then() but somehow it still executes (and passes the arguments) properly.
promiseA()
.then(notPromise)
.then(promiseC);
function promiseA() {
return new Promise(function (resolve, reject) {
const string = "a";
resolve(string);
});
}
function notPromise(string) {
const nextString = "b"
const finalString = string + nextString;
return finalString;
}
function promiseC(string) {
return new Promise(function (resolve, reject) {
const nextString = "c";
const finalString = string + nextString;
alert(finalString);
resolve(finalString);
});
}
The then() method returns a Promise.
See docs.
A promise has a handler method. Once a Promise is fulfilled or rejected, the respective handler function will be called asynchronously. The behavior of the handler function follows a specific set of rules as stated here.
Let's go over them one by one. Here is the code we will inspect side by side. Its nothing special, just a chain of promises returning values.
let sequence = new Promise(function (resolve) {
console.log('Say 1')
resolve(1)
})
sequence
.then(() => {
console.log('Say 2')
return 2
})
.then(() => {
console.log('Say 3')
})
.then(() => {
console.log('Say 4')
return Promise.resolve(4)
})
.then(() => {
return new Promise(function (resolve) {
console.log('Say 5')
setTimeout(() => { resolve(5) }, 1000)
})
})
returns a value, the promise returned by then gets resolved with the returned value as its value;
In code, this is Say 2, and your original question. When a value is returned, then() returns a Promise which is resolved with the value your returned.
doesn't return anything, the promise returned by then gets resolved with an undefined value;
same as above.
throws an error, the promise returned by then gets rejected with the thrown error as its value;
same as above, except now then() returns a Promise which is rejected with your error.
returns an already resolved promise, the promise returned by then gets resolved with that promise's value as its value;
In code this is Say 4, where the promise has already been resolved. So now then() returns a Promise which is resolved with the value 4.
returns an already rejected promise, the promise returned by then gets rejected with that promise's value as its value;
same as above, except it now rejects.
returns another pending promise object, the resolution/rejection of the promise returned by then will be subsequent to the resolution/rejection of the promise returned by the handler. Also, the value of the promise returned by then will be the same as the value of the promise returned by the handler.
In code, this is Say 5. If you return a promise which has not been resolved yet, then() will return a Promise with the results of your promise i.e. 5.
One thing to note, that I also actually learned recently (suggested by #Bergi in comments) was that the then() method always constructs and returns a new Promise before the chain callbacks have even started to execute. The callbacks that you pass to then() simply tells the promise the value/error that the promise should resolve/reject with.
In summary, that is why then() chaining works even when you don't specifically return a new Promise - because then() method always constructs a new promise behind the scenes and rejects/resolves that promise with the value you returned. The most complex case in above scenarios is when you return a Promise in your callback, in which case your callback promise's results are passed to the then() promise.
It has to do with the promise chain, it doesn't matter if subsequent calls to then() are not promises, they are all part of the promise chain, the good thing is you can continue chaining promises, which allows you to do several async/promise operations in a row (as your example described), here is a real world example:
// This is the generic http call
private callServer(url: string, method: string, body?: any) {
const uri = env.apiUrl + url;
const session = this.sessionToken;
const headers = {
'Content-Type': 'application/json',
'credentials': 'same-origin',
'x-auth-token': session,
};
return fetch(uri, {
method,
headers,
body: JSON.stringify(body),
})
.then(this.wait) // this is a timer, returns a promise
.then(this.checkStatus) // this is a sync call
.then((r) => r.text()) // r.text() is async
.then((tx) => tx ? JSON.parse(tx) : {}); // this is sync
}
You can read more about the promise chain here
If I have two promises A and B, only one of which will succeed, how can I get whichever one fulfills successfully? I'm looking for something similar to Promise.race, but which will return only the first promise that fulfills. I'm using promises from ES6.
Invert the polarity of the promises, and then you can use Promise.all, because it rejects on the first rejected promise, which after inversion corresponds to the first fulfilled promise:
const invert = p => new Promise((res, rej) => p.then(rej, res));
const firstOf = ps => invert(Promise.all(ps.map(invert)));
// Utility routines used only in testing.
const wait = ms => new Promise(res => setTimeout(() => res(ms), ms));
const fail = f => Promise.reject(f);
const log = p => p.then(v => console.log("pass", v), v => console.log("fail", v));
// Test.
log(firstOf([wait(1000), wait(500) ]));
log(firstOf([wait(1000), fail("f1")]));
log(firstOf([fail("f1"), fail("f2")]));
This will return the value of the first fulfilled promise, or if all reject, an array of rejection reasons.
ES2021 / ES12 - Promise.any
Promise.any - first fulfilled Promise wins.
const promiseA = Promise.reject();
const promiseB = new Promise((resolve) => setTimeout(resolve, 100, 'succeed'));
const promises = [promiseA, promiseB];
Promise.race(promises).then((value) => console.log(value)); // rejected promise
Promise.any(promises).then((value) => console.log(value)); // "succeed"
Notice that any is ignoring the first rejected promise - promiseA because promiseB is being resolved
If all of the given promises are rejected, then the returned promise is rejected.
This is finished proposal and it's scheduled for ES2021 (expected to be released in June 2021)
If you want the first promise that resolves successfully and you want to ignore any rejections that come before that, then you can use something like this:
// returns the result from the first promise that resolves
// or rejects if all the promises reject - then return array of rejected errors
function firstPromiseResolve(array) {
return new Promise(function(resolve, reject) {
if (!array || !array.length) {
return reject(new Error("array passed to firstPromiseResolve() cannot be empty"));
}
var errors = new Array(array.length);
var errorCntr = 0;
array.forEach(function (p, index) {
// when a promise resolves
Promise.resolve(p).then(function(val) {
// only first one to call resolve will actually do anything
resolve(val);
}, function(err) {
errors[index] = err;
++errorCntr;
// if all promises have rejected, then reject
if (errorCntr === array.length) {
reject(errors);
}
});
});
});
}
I don't see how you can use Promise.race() for this because it simply reports the first promise to finish and if that first promise rejects, it will report a rejection. So, it is not doing what you asked in your question which is to report the first promise that resolves (even if some rejections finished before it).
FYI, the Bluebird promise library has both Promise.some() and Promise.any() which can handle this case for you.
I had the same question and gave it a go. You learn a lot by trying these problems yourself!
The accepted answer is very elegant but uses Promise.all which takes the fun for someone learning Promises; also a bit hard to follow imo.
jfriend00's answer is similar to mine but has that logic that goes beyond the Promises fundamentals which is most important here.
I have made use of those nice helper functions present on the accepted answer:
function firstPromise(promiseL, promiseR) {
return new Promise((resolve, reject) => {
promiseL.then(l => {
resolve(l);
}).catch(error => null);
promiseR.then(r => {
resolve(r);
}).catch(error => null);
promiseL.catch(errorL => {
promiseR.catch(errorR => {
reject(errorL + errorR);
})
})
})
}
const wait = ms => new Promise(res => setTimeout(() => res(ms), ms));
const log = p => p.then(v => console.log("pass", v), v => console.log("fail", v));
log(firstPromise(wait(1000), wait(500)));
log(firstPromise(wait(1000), Promise.reject("Bar")));
log(firstPromise( Promise.reject("Foo"), wait(500)));
log(firstPromise( Promise.reject("Foo"), Promise.reject("Bar")));
//example 1
var promise_A = new Promise(function(resolve, reject) {
// выполнить что-то, возможно, асинхронно…
setTimeout(function(){
return resolve(10);
//return reject(new Error('ошибка'))
},10000)
});
var promise_B = new Promise(function(resolve, reject) {
// выполнить что-то, возможно, асинхронно…
setTimeout(function(){
return resolve(100);
},2000)
});
/*
//[100,10]
Promise.all([
promise_A,promise_B
]).then(function(results){
console.log(results)
});
*/
//100
Promise.race([
promise_A,promise_B
]).then(function(results){
console.log(results)
});
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);
}