Javascript 如何从异步函数返回承诺?
当我尝试从异步函数返回承诺时,无法区分返回的承诺和函数的状态Javascript 如何从异步函数返回承诺?,javascript,es6-promise,Javascript,Es6 Promise,当我尝试从异步函数返回承诺时,无法区分返回的承诺和函数的状态 我认为,最简单的解决方案是将要返回的承诺放在一个数组中。下面是一个愚蠢的例子,但我希望它能说明问题所在: function loadMetaData(id) {/*...*/} // Returns Promise<MetaData> function loadSingleData(name) {/*...*/} // Returns Promise<SingleData> async function st
我认为,最简单的解决方案是将要返回的承诺放在一个数组中。下面是一个愚蠢的例子,但我希望它能说明问题所在:
function loadMetaData(id) {/*...*/} // Returns Promise<MetaData>
function loadSingleData(name) {/*...*/} // Returns Promise<SingleData>
async function startLoadingSingleData(id, object) {
const metaData = object.metaData = await loadMetadata(id);
const singleDataPromise = loadSingleData(metaData.dataToLoad);
singleDataPromise.then(metaData => object.metaData = metaData);
return [singleDataPromise];
}
async function logData(id) {
const object = new SomeUsefulClassWhatTakesAdvantageOfMetadataProp();
somePromise = (await startLoadingSingleData(id))[0];
// Now metadata surely loaded, do something with it
console.log(object.metaData);
// But somedata will be loaded only in future
somePromise.then(singleData => console.log(singleData));
// And maybe: (depends of use-case)
await somePromise;
}
在执行logData/*…*/时,首先在短时间内获取给定数据的给定ID的元数据,然后等待一段时间,然后获取完整的singleData
但这有点老套
克服这种情况的预期方法是什么
附言:
这个问题也会出现,当我试图返回一个承诺,而这个承诺又能解决问题。你的问题是惊人的加载SingleData有太多的责任。它负责加载元数据和触发加载singledata
logData函数使用await StartingsIngleDataId作为确保元数据可用的一种方法,这似乎不是很直观。startLoadingSingleDataid返回一个承诺并不明显,该承诺会在元数据加载时解析,对于第一次查看它的程序员或几个月后查看它的您自己来说,这将是相当混乱的。代码应该尽可能地自我记录,这样就不需要用注释解释每一行
我的建议是完全删除startingsingledata函数,只需在logData中执行此操作:
或者,如果您不希望logData等待SingleData承诺:
async function logData(id) {
const metaData = await loadMetadata(id);
console.log(metaData);
loadSingleData(metaData.name).then( singleData => {
console.log(singleData);
} );
}
如果您真的想继续使用函数startingLoadingLeData,那么我认为您应该让它返回一个数组或一个包含两个承诺的对象:
function startLoadingSingleData(id) {
const metaDataLoaded = loadMetadata(id);
const singleDataLoaded = metaDataLoaded.then(
metaData => loadSingleData(metaData.dataToLoad)
);
return { metaDataLoaded, singleDataLoaded };
}
然后,您的用法将类似于:
async function logData(id) {
const { metaDataLoaded, singleDataLoaded } = startLoadingSingleData(id);
const metaData = await metaDataLoaded;
console.log(metaData);
const singleData = await singleDataLoaded;
console.log(singleData);
}
是的,不幸的是JS的承诺不是代数的,也不是逻辑的。除了不使用本机承诺和不使用async/await之外,没有其他方法可以解决这个问题 最简单和最常见的解决方案实际上是使用包装器对象。你的问题自然会出现:
// takes an id, returns a Promise<{metaData: Data, singleDataPromise: Promise<Data>}>
async function startLoadingSingleData(id) {
const object = new SomeUsefulClassWhatTakesAdvantageOfMetadataProp();
object.metaData = await loadMetadata(id);
// ^^^^^
object.singleDataPromise = loadSingleData(object.metaData.dataToLoad);
// ^ no await here
return object;
}
async function logData(id) {
const object = await startLoadingSingleData(id));
// Now metadata surely loaded, do something with it
console.log(object.metaData);
// But some singleData will be loaded only in future
const singleData = await object.singleDataPromise;
console.log(singleData);
}
无法区分返回的承诺和函数的状态-我不知道这是什么意思。最简单的解决方案是将要返回的承诺放在数组中-异步函数必须返回承诺,而不是数组,即使该数组包含承诺。异步函数自动返回承诺。无论您从异步函数返回什么值,都将自动包装在承诺中。如果您确实执行异步函数{returnnewpromise…},那么您实际上是在返回一个Promise的Promise。除非这是你所需要的,否则你不需要自己创造承诺,只要回报你的价值。谢谢大家,更新。我希望现在这澄清了返回承诺的必要性,以及我的意思。好吧,我忘了:这就是a,b=getPromises;等待时机;等待b;。当loadMetaData拒绝时,您将从singleDataLoaded承诺中获得未处理的承诺拒绝:-
// takes an id, returns a Promise<{metaData: Data, singleDataPromise: Promise<Data>}>
async function startLoadingSingleData(id) {
const object = new SomeUsefulClassWhatTakesAdvantageOfMetadataProp();
object.metaData = await loadMetadata(id);
// ^^^^^
object.singleDataPromise = loadSingleData(object.metaData.dataToLoad);
// ^ no await here
return object;
}
async function logData(id) {
const object = await startLoadingSingleData(id));
// Now metadata surely loaded, do something with it
console.log(object.metaData);
// But some singleData will be loaded only in future
const singleData = await object.singleDataPromise;
console.log(singleData);
}
async function logData(id) {
const object = new SomeUsefulClassWhatTakesAdvantageOfMetadataProp();
object.metaData = await loadMetadata(id);
// Now metadata surely loaded, do something with it
console.log(object.metaData);
// But some singleData will be loaded only in future
object.singleData = await loadSingleData(object.metaData.dataToLoad);
console.log(object.singleData);
}