В настоящее время я пытаюсь создать массив пар с асинхронными вызовами в javascript, но я просто не могу получить его в правильном порядке.
generateDataPoints: function (iterable, source, arg) {
let pairs = []
let prevTime = 0
for (let index in iterable) {
let event = iterable[index]
getTime(event.valueOf()).then(function (time) {
query(source[arg], event.valueOf()).then(function(val) {
if (time !== prevTime) {
prevTime = time
pairs.push([time, val])
console.log(pairs) // This works as expected but only happens after the program returns
} else {
Promise.resolve()
}
})
})
}
return Promise.resolve(pairs)
}
Проблема в том, что команда "pairs.push.." происходит после того, как я вернусь. Я не могу понять, что именно происходит, и как я могу синхронизировать этот процесс. Любая помощь приветствуется.
Вы смешиваете синхронный код (например, цикл for) с асинхронным кодом. Попробуйте что-то вроде этого:
function generateDataPoints(iterable, source, arg) {
let prevTime = 0
[...iterable].reduce((promiseChain, event) => {
let pairs;
return promiseChain
.then(p => {
pairs = p;
return Promise.all([
getTime(event.valueOf()),
query(source[arg], event.valueOf())
])
})
.then(([time, val]) => {
if (time !== prevTime) {
prevTime = time
return pairs.concat([[time, val]]);
} else {
return pairs;
}
});
})
}, Promise.resolve([]));
}
Это уменьшает iterable
до последовательной цепочки Promise, которая в конечном итоге будет содержать все пары.
Если ваша среда позволяет это, вы также можете преобразовать свою функцию с небольшими изменениями в функцию async:
generateDataPoints: async function (iterable, source, arg) {
let pairs = []
let prevTime = 0
for (let index in iterable) {
let event = iterable[index]
const [time, val] = await Promise.all([
getTime(event.valueOf()),
query(source[arg], event.valueOf())
]);
if (time !== prevTime) {
prevTime = time
pairs.push([time, val])
}
}
return pairs;
}
Изменить:
При ближайшем рассмотрении не похоже, что вам нужно секвестировать эти обещания. Вместо этого вы можете запускать их параллельно:
function generateDataPoints(iterable, source, arg) {
Promise.all(
[...iterable].map(event => Promise.all([
getTime(event.valueOf()),
query(source[arg], event.valueOf())
])
).then(pairs => {
let prevTime = 0
return pairs.filter(([time, val]) => {
if (time !== prevTime) {
prevTime = time;
return true;
} else {
return false;
}
});
});
}
Promise.map
которые делают вещи еще проще.