I have been trying to understand the difference between the following two and which is the idle way to use:
let getClient = () => {
return connect()
.then((client) => {
return Promise.resolve(client);
})
.catch((err) => {
return Promise.reject(err);
}
}
and
let getClient = () => {
return connect()
.then((client) => {
Promise.resolve(client);
})
.catch((err) => {
Promise.reject(err);
}
}
and
let getClient = () => {
return new Promise((resolve, reject) => {
return connect()
.then((client) => {
resolve(client);
})
.catch((err) => {
reject(err);
})
})
}
can someone help me understand the difference? Does return Promise.resove/reject make a difference to just using Promise.resolve/reject ?
They are all poor examples.
connect() is thenable, so it presumably returns a promise. Creating extra promises that do nothing except return the results of another promise just over complicates things.
You could rewrite the whole thing as:
let getClient = connect;
… and get something that is more-or-less identical (unless you were then going to go and apply some weird edge cases).
Your first example takes the results of resolving the connect promise, creates a new promise and immediately resolves it with the same value, then returns that promise which is adopted by the connect promise.
Your second example does the same thing, except without the adoption, so the original connect promise results are available in the next then in the chain. (These results are identical to the ones that stepped through the extra promise in the previous example).
Your third example creates a new promise outside the call to connect, and then resolves that with the value from connect. It's another pointless extra promise.
A good question. In your example, first and last snippet yields the same result. But the second one will give you undefined as you are not returning a promise. Also the time taken/sequence of operation differs.
const connect = (input) => new Promise((res, rej) => (!!input ? res('Success') : rej('Failure')));
let getClient_0 = (input) => {
return connect(input)
.then((client) => {
return Promise.resolve(client);
})
.catch((err) => {
return Promise.reject(err);
})
}
let getClient_1 = (input) => {
return connect(input)
.then((client) => {
Promise.resolve(client);
})
.catch((err) => {
Promise.reject(err);
})
}
let getClient_2 = (input) => {
return new Promise((resolve, reject) => {
return connect(input)
.then((client) => {
resolve(client);
})
.catch((err) => {
reject(err);
})
})
}
getClient_0(1).then((r) => console.log('getClient_0 -> ',r)).catch(e => console.log('getClient_0 -> ',e));
getClient_0(0).then((r) => console.log('getClient_0 -> ',r)).catch(e => console.log('getClient_0 -> ',e));
getClient_1(1).then((r) => console.log('getClient_1 -> ',r)).catch(e => console.log('getClient_1 -> ',e));
getClient_1(0).then((r) => console.log('getClient_1 -> ',r)).catch(e => console.log('getClient_1 -> ',e));
getClient_2(1).then((r) => console.log('getClient_2 -> ',r)).catch(e => console.log('getClient_2 -> ',e));
getClient_2(0).then((r) => console.log('getClient_2 -> ',r)).catch(e => console.log('getClient_2 -> ',e));
Related
const setTimeoutProm = (delay) => new Promise(res => setTimeout(() => res(delay),delay))
I want to do something like,
const asyncOpr = (delay) => {
return new Promise((resolve, reject) => {
//update delay for some reason.
const updatedDelay = delay * 2;
setTimeoutProm(updatedDelay).then(res => {
resolve(res);
}).catch(err => {})
})
}
asyncOpr(2000).then(() => alert("resolved")) //this works
This works as expected, but I am not sure if this is correct way of doing this or is there any better way of doing this ?
No, actually the way you do it is an antipattern.
You can just return a promise from the function:
const asyncOpr = (delay) => {
return setTimeoutProm(delay);
};
If needed, a Promise could also be returned from inside a .then:
doA()
.then(() => setTineoutProm(1000))
.then(() => doB());
Or it can also be awaited inside an async function:
async function asyncOpr(delay) {
//...
await setTimeoutProm(delay);
//...
}
I'm trying to limit the number of apis fetches in my project by saving them in a simple cache, key collection in mongodb. Is thera way to stop propagation of .then() inside Promise, without using async/await?
export const getData = (url: string) => {
return new Promise((resolve, reject) => {
findInCache(url)
.then((cached: string | null) => {
if (cached) {
resolve(cached);
}
})
.then(() => {
axios
.get(url)
.then(({data}) => {
setCache(url, data, TTL);
resolve(data);
})
.catch(e => reject(e));
});
});
};
Firstly, lets get rid of the Promise constructor anti-pattern - your function call inside the promise executor returns a promise, so, no need for anew Promise
Secondly, only run the second request if the result of the first is empty
export const getData = (url) => findInCache(url)
// here we return haveResult and avoid axios.get(url) altogether
.then((haveResult) => haveResult || axios.get(url)
// sometimes nested .then is useful like in this case
.then(({data}) => {
setCache(url, data, TTL);
return data;
})
);
you can just do this instead instead of chaining. if it is in cache then fetch from cache else get from url
export const getData = (url: string) => {
return new Promise((resolve, reject) => {
findInCache(url)
.then((cached: string | null) => {
if (cached) {
resolve(cached);
} else {
axios
.get(url)
.then(({data}) => {
setCache(url, data, TTL);
resolve(data);
})
.catch(e => reject(e));
}
})
});
};
When you return something result in then, this result is come into next then function. So, you can control what you would do in next then based on input parameter inCache. So you can do something like:
export const getData = (url: string) => {
return new Promise((resolve, reject) => {
findInCache(url)
.then((cached: string | null) => {
if (cached) {
resolve(cached);
return true;
}
return false;
})
.then((inCache) => {
if (!inCache) {
axios
.get(url)
.then(({data}) => {
setCache(url, data, TTL);
resolve(data);
})
.catch(e => reject(e));
}
});
});
};
I was trying to understand the difference between resolve(thenable) and resolve('non-thenable-object').
In examples below, use promise instead of thenable because promise is also thenable and may be easier to understand.
Demo1: resolve(promise)
let resolvePromise = new Promise(resolve => {
let resolvedPromise = Promise.resolve()
resolve(resolvedPromise)
})
resolvePromise.then(() => {
console.log('resolvePromise resolved')
})
let resolvedPromiseThen = Promise.resolve().then(res => {
console.log('promise1')
})
resolvedPromiseThen
.then(() => {
console.log('promise2')
})
.then(() => {
console.log('promise3')
})
result:
promise1
promise2
resolvePromise resolved
promise3
Demo2: resolve('non-thenable-object')
let resolvePromise = new Promise(resolve => {
resolve('non-thenable-object')
})
resolvePromise.then(() => {
console.log('resolvePromise resolved')
})
let resolvedPromiseThen = Promise.resolve().then(res => {
console.log('promise1')
})
resolvedPromiseThen
.then(() => {
console.log('promise2')
})
.then(() => {
console.log('promise3')
})
result:
resolvePromise resolved
promise1
promise2
promise3
So, I checked the spec and found Promise Resolve Functions
. Then got to PromiseResolveThenableJob and EnqueueJob.
So, according to the spec, I think demo1 was like
Demo3:
let resolvePromise = new Promise(resolve => {
let resolvedPromise = Promise.resolve()
// resolve(resolvedPromise)
// works like
Promise.resolve().then(() => {
Promise.resolve(resolvedPromise).then(() => {
resolve()
})
})
})
resolvePromise.then(() => {
console.log('resolvePromise resolved')
})
let resolvedPromiseThen = Promise.resolve().then(res => {
console.log('promise1')
})
resolvedPromiseThen
.then(() => {
console.log('promise2')
})
.then(() => {
console.log('promise3')
})
I think so because Promise Resolve Functions says:
Perform EnqueueJob("PromiseJobs", PromiseResolveThenableJob, « promise, resolution, thenAction »).
And PromiseResolveThenableJob says:
This Job uses the supplied thenable and its then method to resolve the given promise. This process must take place as a Job to ensure that the evaluation of the then method occurs after evaluation of any surrounding code has completed.
Also, I think demo2 works like
Demo4:
//let resolvePromise = new Promise(resolve => {
//resolve('str')
//})
//works like
let resolvePromise = Promise.resolve('str')
resolvePromise.then(() => {
console.log('resolvePromise resolved')
})
let resolvedPromiseThen = Promise.resolve().then(res => {
console.log('promise1')
})
resolvedPromiseThen
.then(() => {
console.log('promise2')
})
.then(() => {
console.log('promise3')
})
As the Promise Resolve Functions says:
If IsCallable(thenAction) is false, then Return FulfillPromise(promise, resolution).
Though the results between Demo1-Demo3 and Demo2-Demo4 are equal, I am still not sure if I was right. So, I am here to ask
whether my logic is right? If not, how do you explain the different orders
between resolve(thenable) and resolve(non-thenable) ?
Yes, your logic looks right.
new Promise(resolve => resolve('non-thenable-object')) is equivalent to Promise.resolve('non-thenable-object') for all purposes.
In your Demo3 I would however recommend to leave out Promise.resolve(resolvedPromise). I'm not sure whether that was intentional or not, but Promise.resolve does have a shortcut when its argument is already a promise, and then returns the resolvedPromise as-is. You'd rather write
new Promise((resolve, reject) => {
let resolvedPromise = Promise.resolve();
// resolve(resolvedPromise) works like
Promise.resolve().then(() => resolvedPromise.then(resolve, reject));
});
After reading the specification and testing many times I thought I might get it.
Before we start, we have to settle something.
let's call it RESOLVE() when using resolve in Promise executor. For example, RESOLVE(thenable) means the code like:
new Promise((resolve,reject)=>{
resolve(thenable)
})
while resolve(thenable) means Promise.resolve(thenable)
Ok, let's begin.
Promise.resolve('non-thenable') and RESOLVE('non-thenable')
When we are using Promise.resolve('non-thenable') it comes to Promise.resolve
Then it comes to PromiseResolve
That's the where Promise.resolve('non-thenable') was transformed to
new Promise(resolve=>{
resolve('non-thenable')
})
So, we have the conclusion:
Promise.resolve('non-thenable') can be transformed into RESOLVE('non-thenable')
RESOLVE(thenable)
demo1
let resolveThenable = new Promise((resolve, reject) => {
let thenable = {
then: function (resolve, reject) {
console.log('in thenable')
resolve(42)
}
}
resolve(thenable)
// works like
// Promise.resolve().then(() => {
// thenable.then(resolve)
// })
// should be ?
// Promise.resolve().then(() => {
// thenable.then.[[Value]](resolve)
// })
// equivalent to?
// Promise.resolve().then(() => {
// thenable.then(resolve)
// })
})
resolveThenable.then(() => {
console.log('resolveThenable resolved')
})
let resolvedPromiseThen = Promise.resolve().then(res => {
console.log('promise1')
})
resolvedPromiseThen
.then(() => {
console.log('promise2')
})
.then(() => {
console.log('promise3')
})
// 'in thenable'
// 'promise1'
// 'resolveThenable resolved'
// 'promise2'
// 'promise3'
According to Promise Resolve Functions, when we were using RESOLVE(thenable) it comes to
Then it comes to PromiseResolveThenableJob
This would make RESOLVE(thenable) works like
Promise.resolve().then(() => {
thenable.then.[[Value]](resolve)
})
So, I thought it is equivalent to
Promise.resolve().then(() => {
thenable.then(resolve)
})
Which got the same result as RESOLVE(thenable).
So, we can say RESOLVE(thenable) can be transformed to
Promise.resolve().then(() => {
thenable.then(resolve)
})
demo2
let resolvePromise = new Promise((resolve, reject) => {
let resolvedPromise = Promise.resolve()
resolve(resolvedPromise)
// works like
// Promise.resolve().then(() => {
// resolvedPromise.then(() => {
// resolve()
// })
// })
// should be?
// Promise.resolve().then(() => {
// resolvedPromise.then.[[Value]](resolve,reject)
// })
// equivalent to ?
// Promise.resolve().then(() => {
// resolvedPromise.then(resolve)
// })
// equivalent to ?
// Promise.resolve().then(() => {
// resolvedPromise.then(() => {
// resolve()
// })
// })
})
resolvePromise.then(() => {
console.log('resolvePromise resolved')
})
let resolvedPromiseThen = Promise.resolve().then(res => {
console.log('promise1')
})
resolvedPromiseThen
.then(() => {
console.log('promise2')
})
.then(() => {
console.log('promise3')
})
// 'promise1'
// 'promise2'
// 'resolvePromise resolved'
// 'promise3'
When we talked about RESOLVE(resolvedPromise), we can find the spec doesn't distinguish thenable from promise. So, in the same way, RESOLVE(resolvedPromise) can be transformed into
Promise.resolve().then(() => {
resolvedPromise.then(resolve)
})
Though, in this case, the order between RESOLVE(thenable) and RESOLVE(promise) is different. Because thenable.then is a sync operation while resolvedPromise.then is an async operation. They are not the same then method.
So, here is our conclusion:
Both RESOLVE(thenable) and RESOLVE(promise) can be transformed into
new Promise((resolve, reject) => {
Promise.resolve().then(() => {
thenable.then(resolve)
})
})
Promise.resolve(thenable)
It is quite simple when using Promise.resolve(promise) because it returns promise argument.
However, things become complicated when using Promise.resolve(thenable) and the thenable is not a promise. Let's call it Promise.resolve(nonPromiseThenable).
According to Promise.resolve ( x )
Then it comes to
So, Promise.resolve(nonPromiseThenable) can be transformed to
new Promise(resolve => {
resolve(nonPromiseThenable)
})
And finally comes to
new Promise(resolve => {
Promise.resolve().then(() => {
nonPromiseThenable.then(resolve)
})
})
You can test it in the demo below.
var thenable = {
then(resolve, reject) {
resolve(1)
}
}
// code transformation
Promise.resolve(thenable).then(res => {
console.log(res)
})
// equal
// new Promise(resolve => {
// resolve(thenable)
// }).then(res => {
// console.log(res)
// })
// equal
// new Promise(resolve => {
// Promise.resolve().then(() => {
// thenable.then(resolve)
// })
// }).then(res => {
// console.log(res)
// })
new Promise(resolve => resolve(2))
.then(res => {
console.log(res)
})
.then(res => console.log(3))
In the end, let's make a conclusion:
Promise.resolve('nonThenable') can be transformed into RESOLVE('nonThenable'). They have the same effects.
Promise.resolve(thenable) is different from RESOLVE(thenable). They have different effects.
RESOLVE(thenable) and RESOLVE(promise) can be transformed into
new Promise((resolve, reject) => {
Promise.resolve().then(() => {
thenable.then(resolve)
})
})
Promise.resolve(promise) === promise while Promise.resolve(nonPromiseThenable) can be transformed into
new Promise(resolve => {
Promise.resolve().then(() => {
nonPromiseThenable.then(resolve)
})
})
I'm a little confused about the usage of Promise.
Please see the examples below:
Q1. How can I stop the chain call?
const wait = (duration = 0) => {
return new Promise((resolve) => {
setTimeout(resolve, duration);
});
};
const asyncTask1 = () => {
return wait(1000).then(() => {
console.log('task1 takes 1s.');
});
};
const asyncTask2 = () => {
return wait(3000).then(() => {
console.log('task2 takes 3s.');
});
};
Promise.resolve()
.then(() => {
asyncTask1();
})
.then(() => {
asyncTask2();
})
.catch(() => {
console.log('fail.');
});
As the code shows, asyncTask2 won't run until asyncTask1 has completed. But the question is how can I stop the chain call if asyncTask1 fails. Namely asyncTask2 won't run because the asyncTask1 fails
.
Note: no error or exception generated in asyncTask1, I want to use a status (success or failed) to decide the result of asyncTask1.
Q2. How can I know which task generates the exception when I use Promise.all()?
const wait = (duration=0) => {
return new Promise((resolve) => {
setTimeout(resolve, duration);
});
};
const asyncTask1 = () => {
return wait(1000).then(() => {
console.log('task1 takes 1s.');
});
};
const asyncTask2 = () => {
return wait(3000).then(() => {
console.log('task2 takes 3s.');
});
};
Promise
.all([asyncTask2(), asyncTask1()])
.then(() => {
console.log('all done.');
})
.catch((e) => {
console.log('error');
});
The code above can run successfully, but if asyncTask1 or asyncTask2 fails, it will go into the catch function. So the question is how can I know whether the exception is from asyncTask1 or asyncTask2?
You can use Array.prototype.map() to call the functions set at an array, throw the index of the element where error occurs within .map() callback at .catch()
const wait = (duration=0) => {
return new Promise((resolve) => {
setTimeout(resolve, duration);
});
};
const asyncTask1 = () => {
return wait(1000).then(() => {
console.log('task1 takes 1s.');
});
};
const asyncTask2 = () => {
return wait(3000).then(() => {
throw new Error()
console.log('task2 takes 3s.');
});
};
let arr = [asyncTask2, asyncTask1];
Promise
.all(arr.map((p, index) =>
p().catch(err => {throw new Error(err + " at index " + index)})))
.then(() => {
console.log('all done.');
})
.catch((e) => {
console.log('error', e);
});
Without the use of any extra libraries (async, bluebird etc) I am trying to implement a function that returns a promise resolves (or rejects) based on an array of functions that return promises as an input parameter... Promise.all(iterable) has very similar functionality to what I am trying to accomplish exepct the promises in the iterable parameter of Promise.all do not execute in sequential order.
I could simply chain these functions together however what if functionListwas a list of unkown length...
I have attemped to conceptually show what I am trying to accomplish below:
function foo() {
return new Promise((resolve, reject) => {
setTimeout( () => {
return resolve();
}, 200);
})
}
function bar() {
return new Promise((resolve, reject) => {
setTimeout( () => {
return resolve();
}, 200);
})
}
function baz() {
return new Promise((resolve, reject) => {
setTimeout( () => {
return reject();
}, 100);
})
}
const functionList = [foo, bar, baz];
function promiseSeries(functionList){
const results = [];
return new Promise((resolve, reject) => {
promiseList.map((promise, i) => {
return new Promise((_resolve, _reject) => {
promise()
.then((result) => {
results.push(result);
if (i === promiseList.length - 1) {
return resolve(results);
}
else return _resolve();
})
.catch(error => error)
})
})
})
}
Obviously with running Promise.all on functionList we will see that baz (even though its position is functionList[2] resolves first)
Neither Resolve promises one after another (i.e. in sequence)? or Running promises in small concurrent batches (no more than X at a time) provide answers to this question. I do not want to import a library to handle this single utility function and mostly I am just curious as to what this function would look like.
This is not more complicated than:
funcs.reduce((prev, cur) => prev.then(cur), Promise.resolve())
A recursive version, which return an array of the resolved values:
function recurse([first, ...last], init) {
if (!first) return Promise.resolve([]);
return first(init)
.then(value =>
recurse(last, value)
.then(values => [value, ...values])
);
}
// Testing function to return a function which
// returns a promise which increments its value.
const x = v => y => Promise.resolve(v + y);
recurse([x(1), x(2)], 0).then(console.log);
A nice and clean way to achieve this without any extra libraries is using recursion. An example:
const p1 = () => Promise.resolve(10);
const p2 = () => Promise.resolve(20);
const p3 = () => Promise.resolve(30);
const promiseList = [p1, p2, p3];
const sequencePromises = (promises) => {
const sequence = (promises, results) => {
if (promises.length > 0) {
return promises[0]()
.then(res => sequence(promises.splice(1, promises.length), results.concat(res)))
.catch(err => Promise.reject(err));
} else {
return Promise.resolve(results);
}
}
return sequence(promises, []);
}
sequencePromises(promiseList)
.then(res => console.log(res))
.catch(err => console.log("ERROR"));
The simplest way is to just chain them, starting with a null promise:
const promises = [foo, bar, baz];
let result = Promise.resolve();
promises.forEach(promise => result = result.then(() => promise));
return result;
As Ali pointed out, you can use a reduction instead but you need to use functions in the then calls:
return promises.reduce(
(result, promise) => result.then(() => promise),
Promise.resolve()
);
You can omit the initial value if you know that promises is not empty.
However if you really want to do things in sequence, you often want to deal with an array of functions that return a promise. For example:
return ids.map(id => () => processId(id))
.reduce((p, fn) => p.then(fn), Promise.resolve());
promises.reduce((previous, promise) => {
if (previous) {
return previous.then(() => promise);
}
return promise;
}, null)