I have this bit of code:
const promises = new Array(20).fill(null).map(v => {
return c.lockp('foo').then((v => {
const rand = Math.random()*3000;
return new Promise((resolve) => setTimeout(resolve,rand)).then(_ => v);
})
.then(({key, id}) => c.unlockp(key, id)));
});
return Promise.all(promises)
.then(values => {
console.log('all good');
process.exit(0);
});
I am getting this error:
TypeError: (intermediate value)(intermediate value).then is not a
function
at Array.fill.map.v (/home/oleg/WebstormProjects/oresoftware/live-mutex/.r2g/tests/smoke-test.js:26:6)
at Array.map ()
at /home/oleg/WebstormProjects/oresoftware/live-mutex/.r2g/tests/smoke-test.js:20:43
It should be occurring on 5th line of code in the code snippet above.
Your .then is being called on the function with the v parameter (which is enclosed in the parentheses right before the .then). Put the .then outside instead, so that it gets called on the promise chain rather than on the callback:
const promises = new Array(20).fill(null).map(v => {
return c.lockp('foo')
.then(v => {
const rand = Math.random()*3000;
return new Promise((resolve) => setTimeout(resolve,rand)).then(_ => v);
})
.then(({key, id}) => c.unlockp(key, id));
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 was trying to learn how to avoid the anti pattern as described here What is the explicit promise construction antipattern and how do I avoid it?
I started with some code on JSFiddle but it does not output what I expected..
function sum1(x){
return new Promise(resolve => x+1)
}
function sum2(x){
return sum1(x)
.then(x => x+1);
}
function sum3(x){
return sum2(x)
.then(x => x+1)
}
sum3(1)
.then(console.log);
I would expect it to print 4 but it prints nothing
You need to create a resolved promise by using Promise.resolve():
function sum1(x){
return Promise.resolve(x+1)
}
function sum2(x){
return sum1(x)
.then(x => x+1);
}
function sum3(x){
return sum2(x)
.then(x => x+1)
}
sum3(1)
.then(console.log);
you are doing it wrong in sum1. new Promise((resolve, reject) => {//code here}) takes function as argument
function sum1(x){
return new Promise((resolve) => {
resolve(x + 1);
})
}
function sum2(x){
return sum1(x)
.then(x => x+1);
}
function sum3(x){
return sum2(x)
.then(x => x+1)
}
sum3(1)
.then(res => console.log(res));
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));
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)