问题:
I made this dummy code to have a better understanding on how promises work, mimicking a more complex software that I have to "promisify". In the attached code, I wanted the...
可以将文章内容翻译成中文,广告屏蔽插件会导致该功能失效:
问题:
I made this dummy code to have a better understanding on how promises work, mimicking a more complex software that I have to "promisify". In the attached code, I wanted the events to fire and be logged in the following order:
- the "before" string
- the list of "... detected"
- the list of "done with ..."
- the "after" string
But as you can see if you run it, the "after" string is printed between steps 2 and 3. Clearly, I must be doing something wrong in handling async logic. Thanks for your help!
const obj = {
"rows": [{
"type": "A",
"value": 0
}, {
"type": "B",
"value": 0
}, {
"type": "C",
"value": 0
}]
}
let promises = [];
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
const alter_value = async(row, to_add, time) => {
await delay(time);
row.value = row.value + to_add;
console.log("done with " + row.type);
return true;
}
const two = async() => {
obj.rows.forEach(async(row) => {
switch (row.type) {
case "A":
console.log("A detected");
promises.push(alter_value(row, 1, 1000))
promises.push(alter_value(row, 2, 1800))
break;
case "B":
console.log("B detected");
promises.push(alter_value(row, 5, 1400))
break;
case "C":
console.log("C detected");
promises.push(alter_value(row, 200, 2400))
break;
}
});
return promises;
}
const one = async() => {
console.log("before");
Promise.all(two()).then(console.log("after"));
}
one();
回答1:
I see at least two issues with your code, explaining the result you're getting:
- Your
two
function should not be async
. async
functions return an implicit Promise
. Here you just want to return an array of Promise
s that you already construct yourself, so a normal function is what you need.
.then(console.log("after"))
will execute the console.log
right away: then()
expects a function to execute later, so you have to change it to .then(() => console.log("after"))
.
This becomes:
const obj = {
"rows": [{
"type": "A",
"value": 0
}, {
"type": "B",
"value": 0
}, {
"type": "C",
"value": 0
}]
};
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
const alter_value = async (row, to_add, time) => {
await delay(time);
row.value = row.value + to_add;
console.log("done with " + row.type);
return true;
};
const two = () => {
const promises = [];
obj.rows.forEach(async(row) => {
switch (row.type) {
case "A":
console.log("A detected");
promises.push(alter_value(row, 1, 1000));
promises.push(alter_value(row, 2, 1800));
break;
case "B":
console.log("B detected");
promises.push(alter_value(row, 5, 1400));
break;
case "C":
console.log("C detected");
promises.push(alter_value(row, 200, 2400));
break;
}
});
return promises;
};
const one = async () => {
console.log('before');
Promise.all(two()).then(() => console.log('after'));
};
one();
Note that, as an alternative to .then()
, you can simply use await
on Promise.all
as well, to make your code more consistent:
await Promise.all(two());
console.log('after');
回答2:
It looks like the OP requests synchronous behavior.
Demo Outline
function modVal(i, value, time)
parameters are derived from the async function syncro()
parameter: const sync
an array of objects. Each object contains the index of obj.rows
, the value at that index obj.rows[i].value
, and the time for the timeout in the Promise of modVal()
.
Parameters and Arguments: const sync = [{r: 0, v: 1, t: 1000}, ...];
seq.r: obj.rows[
number]
seq.v: obj.rows[seq.r].value +=
number
seq.t: ...resolve(obj.rows[i].value += value),
number);
sync
array is iterated by a for...of
loop. On each iteration await modVal()
is called synchronously.
let obj = {
"rows": [{
"type": "A",
"value": 0
}, {
"type": "B",
"value": 0
}, {
"type": "C",
"value": 0
}]
}
const sync = [{
r: 0,
v: 1,
t: 1000
}, {
r: 0,
v: 2,
t: 1800
}, {
r: 1,
v: 5,
t: 1400
}, {
r: 2,
v: 200,
t: 2400
}];
const syncro = async(sync) => {
const modVal = (i, value, time) => {
return new Promise(resolve => {
setTimeout(() => resolve(obj.rows[i].value += value), time);
});
}
for (let seq of sync) {
await modVal(seq.r, seq.v, seq.t);
console.log(JSON.stringify(obj.rows));
}
}
syncro(sync);
.as-console-row.as-console-row::after {
content:'';
padding:0;
margin:0;
border:0;
width:0;
}