我正在开发一款游戏,代码中有一个位置可以并行加载所有资源。目前它看起来像这样:
let [
grassTexture,
stoneTexture,
waterTexture,
birdSound,
bellSound,
choochooSound
] = await Promise.all([
loadGrassTexture(),
loadStoneTexture(),
loadWaterTexture(),
loadBirdSound(),
loadBellSound(),
loadChoochooSound()
])
但我觉得这不是特别好的设计,因为很容易弄乱顺序(加载器和加载器之间的关联),如果结果与相应的函数调用在同一行会更好。我看到的另一种选择是:
let grassTexturePromise = loadGrassTexture()
let stoneTexturePromise = loadStoneTexture()
let waterTexturePromise = loadWaterTexture()
let birdSoundPromise = loadBirdSound()
let bellSoundPromise = loadBellSound()
let choochooSoundPromise = loadChoochooSound()
let grassTexture = await grassTexturePromise
let stoneTexture = await stoneTexturePromise
let waterTexture = await waterTexturePromise
let birdSound = await birdSoundPromise
let bellSound = await bellSoundPromise
let choochooSound = await choochooSoundPromise
但这也没什么好处。有没有什么惯用的方法可以做到这一点?
编辑:
我很抱歉这是一个不断变化的目标,我在这篇文章中简化了太多内容。在我的代码中,我使用的是 TypeScript,并且资源有不同的类型。我还根据评论更正了第二个列表。
7
最佳答案
4
不要对每个资源使用单独的变量,而是将它们放在以资源名称为键的对象中。
然后您可以使用Promise.all()
循环来填充值。
const textures = {
grass: loadGrassTexture(),
stone: loadStoneTexture(),
// ...
};
const results = await Promise.all(Object.values(textures));
Object.keys(textures).forEach((key, i) => textures[key] = results[i]);
2
-
谢谢!这对我来说看起来最优雅。但是,我认为这不适用于 TypeScript。很抱歉,我忘了说我正在使用 TypeScript…
– -
我不使用 TypeScript,但就我对它的了解,我不明白为什么它不起作用。
–
|
您可以将其重构为参数化函数:
//if you can refactor you code to a parameterized load texture function
async function loadTexture(textureName) {
//your new code here
}
const textureNames = ['grass', 'stone', 'water', 'sky', 'sand', 'wood', 'carpet', 'paper', 'steel'];
const texturePromises = textureNames.map(async (name) => [name, await loadTexture(name)]);
const textureEntries = await Promise.all(texturePromises);
//now we have a mapping of texture type -> texture
const textureObject = Object.fromEntries(textureEntries);
|
我建议创建一个单独的命名空间文件。
例如:
loaders.mjs
// PLACE NECESSARY IMPORTS HERE
// The functions below should return Promises.
export const grassTexture = loadGrassTexture();
export const stoneTexture = loadStoneTexture();
export const waterTexture = loadWaterTexture();
export const skyTexture = loadSkyTexture();
export const sandTexture = loadSandTexture();
export const woodTexture = loadWoodTexture();
export const carpetTexture = loadCarpetTexture();
export const paperTexture = loadPaperTexture();
export const steelTexture = loadSteelTexture();
// The order below doesn't matter...
export default Promise.all
([
grassTexture, stoneTexture, waterTexture,
skyTexture, sandTexture, woodTexture,
carpetTexture, paperTexture, steelTesture,
]);
然后在任何其他文件中,您可以像这样加载它们:
// Import the loaders at the script root.
import texturePromises, * as loaders from './loaders.mjs';
// Then use at an asynchronous thread...
async function installTextures ()
{
// Stops the thread until all Promises are fulfilled.
await texturePromises;
// From here on everything is loaded...
// Note that the order doesn't matter.
const { paperTexture, skyTexture } = loaders;
// Use as needed.
}
// Or import just the needed part for a specific component directly...
import { stoneTexture, grassTexture, waterTexture } from './loaders.mjs';
请注意,该await
关键字将停止线程,直到相应的 Promise 得到满足。确保仅在真正需要时使用。在大多数情况下,最好依赖该.then()
方法。
|
如果你不是特别喜欢原生 JavaScript,你可以考虑使用:
let {
grassTexture,
stoneTexture,
...
} = await Bluebird.props({
grassTexture: loadGrassTexture(),
stoneTexture: loadStoneTexture(),
...
})
|
–
–
*Texture
变量仍然是承诺)2.–
Promise.allSettled
,输出比来自的输出稍微复杂一些Promise.all
,但您会收到哪些被拒绝以及哪些被满足的信息(顺序也被保留)–
–
|