#javascript #node.js #async-await
Вопрос:
Я пытаюсь объединить два значения функции (от a()
и b()
), но код не ожидает оператора await в функции test
, как ожидалось. Вместо этого значение результата выводит непосредственно неправильный результат.
function resData(status, message) {
return { ok: status, message: message };
}
function a() {
return resData(true, 'A');
}
async function b() {
// simulate some long async task (e.g. db call) and then return the boolean result
function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
}); }
await sleep(2500);
return resData(true, 'B');
}
async function isValid() {
const promises = [a, b].map(async (fnc) => { return await fnc().ok; });
const results = await Promise.all(promises);
// combine the results to one boolean value
return results.every(Boolean);
}
async function test() {
// not waiting here
const res = await isValid();
// prints directly - wrong result false
console.log('result', res);
}
test();
После вывода неправильного результата он ждет 2,5 секунды. Я думаю , что это связано с вызовом функции resData
, но я не мог понять сам, где мое непонимание асинхронности / ожидания. Заранее спасибо.
Комментарии:
1.
await fnc().ok
-> >(await fnc()).ok
в противном случае вы только ждетеundefined
, такfnc()
как возвращает обещание, и.ok
по этому обещанию возвращаетсяundefined
.
Ответ №1:
Вместо того, чтобы ждать разрешения функции, вы ожидаете возврата значения функцией.
async function isValid() {
const promises = [a, b].map(async (fnc) => {
//return await fnc().ok;
// You have to await first function then call `.ok` value
return (await fnc()).ok;
});
const results = await Promise.all(promises);
// combine the results to one boolean value
return results.every(Boolean);
}
Просто чтобы упростить проблему, пожалуйста, проверьте приведенный ниже код.
async function test() {
return { ok: true };
}
async function main() {
// trying to await on undefined.. test().ok == undefined
console.log(await test().ok); // undefined
// first await function.. then return ok
console.log((await test()).ok); // true
}
main();
Ответ №2:
Я бы сказал, что есть 2 1 проблема с вашим кодом
— игнорировать, оказывается, можно, кто же знал!a
не возвращал обещание, так что вы не можете относиться к нему как к одному- Вы не можете дождаться логического значения, поэтому
await fnc().ok
в этом нет смысла.
Я бы предложил вам
a
Дайте обещание вернуть, даже если это всего лишь решенное обещание- Выполните только методы в
map
- Прочитайте значение
ok
вevery
вызове, чтобы определить, разрешены ли все обещания с этим значением, равнымtrue
С этими изменениями все работает так, как я подозреваю, вы ожидали, с 2,5-секундным ожиданием перед записью на консоль.
function resData(status, message) {
return { ok: status, message: message };
}
function a() {
return resData(true, 'A');
}
async function b() {
// simulate some long async task (e.g. db call) and then return the boolean result
function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
}); }
await sleep(2500);
return resData(true, 'B');
}
async function isValid() {
const promises = [a, b].map(fnc => fnc());
const results = await Promise.all(promises);
// combine the results to one boolean value
return results.every(x => x.ok);
}
async function test() {
// not waiting here
const res = await isValid();
// prints directly - wrong result false
console.log('result', res);
}
test();
Комментарии:
1. вы действительно можете
await
на обычном (не толькоPromise
) объекте2. Вы можете не только
await
работать с чем угодно, вы также можете использовать статические методы обещания, какPromise.all()
и с чем угодно. Именно потому, что обещание может привести к чему угодно.3. @Jamiec кстати, насколько показывает мой браузер, у вас все еще есть «Вы не можете дождаться логического значения» в ответе.
4. @Jamiec Большое вам спасибо за ваш ответ. Также спасибо за подсказки в разделе комментариев. Я также понятия не имею, откуда взялись все эти понижающие голоса.
5. @Habebit не беспокойся об этом. ТАК что иногда может быть странно, что в твоем вопросе не было ничего плохого.
Ответ №3:
Асинхронные функции неявно возвращают обещание, которое в конечном итоге будет разрешено до конечного значения, возвращаемого по окончании выполнения функции.
Таким образом, вам просто нужно вызвать свои функции внутри map
обратного вызова, чтобы собрать обещания. Массив результатов будет представлять собой массив resData
объектов. Итак, вы, наконец, проверяете каждое ok
свойство на соответствие вашим требованиям.
function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
function resData(status, message) {
return {ok: status, message: message};
}
function a() {
return resData(true, 'A');
}
async function b() {
await sleep(2500);
return resData(true, 'B');
}
async function isValid() {
const promises = [a, b].map((fnc) => fnc());
const results = await Promise.all(promises);
return results.every((result) => result.ok);
}
async function test() {
const res = await isValid();
console.log('result', res);
}
test();
Комментарии:
1. Я имею в виду, в значительной степени копию/вставку моего ответа без незначительной оплошности, но все в порядке.
2. @Jamiec не видел вашего ответа до тех пор, пока я не опубликовал свой. Код был на 99% написан OP, так что на самом деле мы оба скопировали его, и имеет смысл, что ответы похожи (хотя мы писали разные вещи). Наконец, я никого здесь не понижал, но, если вы спросите меня, вы написали много неточных вещей в своем ответе, и вы должны быть уверены в вещах, прежде чем вводить людей в заблуждение.