问题
I have promise objects which need to work synchronize. For example second promise shouldn't work before first one is done. If first one rejects first one has to be executed again.
I have implemented some examples.This one works well. call getVal, wait 2000ms, return, i++, again call getVal .....
getVal() {
return new Promise(function(resolve, reject) {
setTimeout(function(){ resolve(19) }, 2000);
});
}
async promiseController(){
for(var i =0;i<5;i++)
{
var _val = await this.getVal()
console.log(_val+'prom');
}
}
But I need to control an array of promise objects. What I want to do is that I have a data and I divided it 5 pieces. After first part is processed(for example:sent to server) well I want to process second part otherwise I have to process first part again.
This is the prototype implementation I made
getVal() {
return new Promise(function(resolve, reject) {
setTimeout(function(){ resolve(19) }, 2000);
});
}
async promiseController(){
var proms=[]
for(var i =0;i<5;i++)
{
proms.push(this.getVal())
}
for(var i =0;i<5;i++)
{
var _val = await proms[i]
console.log(_val+'prom');
}
}
Promises objects in this code works sequentially. How can i fix the code below so that it works synchronous as first example.
回答1:
async promiseController(){
for(const value of array) {
console.log((await this.getVal(value))+'prom');
}
}
No need to overcomplicate things. Just call await
inside the loop and it'll wait for what you want.
As the other answer rightfully said - a promise represents a value and not an operation. For operations regular functions are used.
If you want to ignore failures you can .catch(() => {})
on the promise. If you want to retry until failures - you can refactor retry to a function and use that:
const retry = fn => (...args) => fn(...args).catch(retry(fn));
回答2:
If your goal is to not "execute the subsequent promises" until the first promise resolves, then you need to keep in mind that promises represent asynchronous activity already in flight. Once the promise exists, it is too late.
You need to instead not call the subsequent promise factory methods until the first promise finishes. Your first example does this by not calling getVal()
until the previous promise completes.
So you end up with something like:
delay(time) {
return new Promise(resolve => setTimeout(resolve, time));
}
async promiseController() {
const factories = [];
for (let i = 0; i < 5; ++i) {
factories.push(() => this.getVal());
}
for (const f of factories) {
// keep running this factory until it succeeds
let success = false;
while (!success) {
try {
const promise = f();
const result = await f;
success = true;
console.log(`result = ${result}`);
}
catch (err) {
console.log("promise failed. retrying");
await delay(100);
}
}
}
}
回答3:
You can use recursion, named function, .then()
var arr = [Promise.resolve("a")
, Promise.resolve("b")
, Promise.resolve("c")];
var i = 0;
var res = [];
function foo() {
// conditional resolved or rejected promise
var n = String(new Date().getTime()).slice(-1);
// if `n` < 5 reject `n` , else resolve `n`
var curr = n < 5;
return curr ? arr[i] : Promise.reject(["rejected", n])
}
var p = (function repeat() {
var promise = foo();
return promise
.then(function(data) {
console.log(data);
res.push(data);
++i;
if (i < arr.length) return repeat()
// return `res` array when all promises complete
else return res
})
.catch(function(err) {
console.log(err);
if (err[0] === "rejected") return repeat()
})
}());
p.then(function(complete) {
console.log("complete:", complete)
});
回答4:
Well OK. I believe for the sake of proper functional programming purposes the async
and await
thingy should be avoided. I believe promises are very sufficient. Yet if you would like to continue coding in C++ ish imperative style then async
and await
is for you.
I have promise objects which need to work synchronize. For example second promise shouldn't work before first one is done. If first one rejects first one has to be executed again.
Let me give a little brief on the code below. We have the async()
function which takes a data and a callback (error first type). As for demo purposes it will try to invoke the callback with data within 2000ms however there is a timeout at 1000ms. So 50-50 it will either invoke the callback with data or error.
So we actually need it to return us a promise so I promisify it with the help of promisify()
and it takes async()
function and returns me the asyncPro()
function. Which is in fact same as async()
but returns a promise instead. So we are expected to use our callback at the then
stage.
Then comes tryNTimes(data,asyncFun,n = 5)
function which takes data, a promisified async function and an integer designating the number of times to try before rejecting it. It's default try count is 5 but you can set it to any value by passing the third argument.
As for the last part we have the flowControl()
which chains up our promises perfectly by the help of Array.prototype.reduce()
.
So now we have all our promises chained one after the other and none will fail before trying 5 times.
function promisify(fun){
return (data) => new Promise((resolve,reject) => fun(data, (err,res) => err ? reject(err) : resolve(res)));
}
function async(data, callback){
var dur = Math.floor(Math.random()*2000);
setTimeout(_ => callback(false,data),dur); // may resolve before timeout
setTimeout(_ => callback("error at " + data),1000); // timeout at 1 sec
}
function tryNTimes(data,asyncFun,n = 5){
return new Promise((resolve,reject) => { n === 0 && reject("try out fail at 5 tries: " + data);
asyncFun(data).then(v => resolve("resolved at countdown " + n + ": " + v))
.catch(e => resolve(tryNTimes(data,asyncFun,--n)));
});
}
function flowControl(d,f,tc){
return d.reduce((prom,chunk) => prom.then(v => { console.log(v);
return tryNTimes(chunk,f,tc);
}),Promise.resolve("initial dummy promise"));
}
var data = ["chunk_1", "chunk_2", "chunk_3", "chunk_4", "chunk_5"],
asyncPro = promisify(async); // now our async function returns a promise
flowControl(data,asyncPro).then(v => console.log(v))
.catch(e => console.log(e));
If you would like to see the "5 times try" errors more frequently please lower the timeout value in async()
function.
来源:https://stackoverflow.com/questions/39213035/how-to-synchronise-promise-objects