#javascript #asynchronous #es6-promise
#javascript #асинхронный #es6-обещание
Вопрос:
Я создал этот фиктивный код, чтобы лучше понимать, как работают обещания, имитируя более сложное программное обеспечение, которое я должен «обещать». В прилагаемом коде я хотел, чтобы события запускались и регистрировались в следующем порядке:
- строка «до»
- список «… обнаружено»
- список «сделано с …»
- строка «после»
Но, как вы можете видеть, если вы запустите его, строка «после» печатается между шагами 2 и 3. Очевидно, я, должно быть, делаю что-то неправильно при обработке асинхронной логики. Спасибо за вашу помощь!
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.
const jsonArray = { ... }
— Это не массив и не массив JSON. Это всего лишь обычный старый объект.2. ты прав, @ Andreas, я исправил его название
Ответ №1:
Я вижу по крайней мере две проблемы с вашим кодом, объясняющие результат, который вы получаете:
- Ваша
two
функция не должна бытьasync
.async
функции возвращают неявноеPromise
значение. Здесь вы просто хотите вернуть массивPromise
s, который вы уже создали самостоятельно, поэтому вам нужна обычная функция. .then(console.log("after"))
console.log
сразу же выполнит:then()
ожидает, что функция будет выполнена позже, поэтому вам нужно изменить ее на.then(() => console.log("after"))
.
Это становится:
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();
Обратите внимание, что в качестве альтернативы .then()
вы также можете просто использовать await
on Promise.all
, чтобы сделать ваш код более согласованным:
await Promise.all(two());
console.log('after');
Ответ №2:
Похоже, что OP запрашивает синхронное поведение.
Демонстрационный план
-
modVal(i, value, time)
параметры функции являются производными отsyncro()
параметра функции async:const sync
массива объектов. Каждый объект содержит индексobj.rows
, значение в этом индексеobj.rows[i].value
и время ожидания в обещанииmodVal()
. -
Параметры и аргументы:
const sync = [{r: 0, v: 1, t: 1000}, ...];
seq.r:obj.rows[
число]
числоobj.rows[seq.r].value =
после t:
число...resolve(obj.rows[i].value = value),
после v:); -
sync
массив повторяетсяfor...of
циклом. На каждой итерацииawait modVal()
вызывается синхронно.
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;
}