导出含Promise结果的对象报错:Cannot access sendToHell before init
问题描述
我正在开发一款支持用户创建交互式故事的应用,现在需要把包含Promise结果的对象导出到其他模块,目标是获取Promise返回的克隆数组,但导出时遇到了问题。我已经把localStorage相关函数改成了异步函数,stored对象里的storedLink、storedHeading等都是已解析的Promise,对应从本地存储获取的数组。
写好代码后运行出现错误:Cannot access sendToHell before init,尝试用this关键字时又出现Cannot read properties of undefined reading res错误。我知道导出导入是同步操作,也试过顶层await(确认处于模块环境)和立即执行函数,但都没解决,求正确的实现方案。
我的代码如下:
export const sendToHell = { res: [], kamino: async function () { this.res = await Promise.all([ stored.storedLink, stored.storedHeading, stored.storedBeginning, stored.storedChoices, stored.storedParts, ]); return this.res; }, cloneLink: [...sendToHell.res[0]], cloneHeading: [...sendToHell.res[1]], cloneBeginning: [...sendToHell.res[2]], cloneChoices: [...sendToHell.res[3]], cloneParts: [...sendToHell.res[4]], }; sendToHell.kamino();
解决方案
问题根源
cloneLink这类属性在对象初始化阶段就尝试访问sendToHell.res,但此时sendToHell还没完全创建完成,直接触发了引用错误。- 就算解决了初始化顺序问题,
res初始是空数组,直接取res[0]会得到undefined,展开操作必然报错。 - 异步操作完成前,克隆属性根本拿不到Promise返回的有效数据。
可行实现方案
因为模块导出是同步操作,但我们依赖异步获取的数据,所以核心思路是让导出的内容能等待异步操作完成后再提供有效数据,下面两种方案都能解决问题:
方案1:导出初始化后的Promise(推荐)
直接把异步获取并克隆数据的逻辑封装成函数,导出它返回的Promise,其他模块通过await拿到最终的克隆数组:
// 异步初始化并克隆数据 async function initStoryData() { // 等待所有Promise resolve const [link, heading, beginning, choices, parts] = await Promise.all([ stored.storedLink, stored.storedHeading, stored.storedBeginning, stored.storedChoices, stored.storedParts, ]); // 返回克隆后的数组集合 return { cloneLink: [...link], cloneHeading: [...heading], cloneBeginning: [...beginning], cloneChoices: [...choices], cloneParts: [...parts] }; } // 导出Promise,其他模块用await获取结果 export const storyData = initStoryData();
其他模块使用方式:
import { storyData } from './你的模块路径.js'; async function useStoryData() { // 等待数据准备完成 const { cloneLink, cloneHeading } = await storyData; // 在这里使用克隆后的数组 }
方案2:导出带初始化方法的对象
如果需要保持对象的结构,可以导出一个包含异步初始化和数据获取方法的对象,确保只有在异步操作完成后才能拿到有效数据:
export const storyStore = { _data: null, // 存储初始化后的克隆数据 // 异步初始化方法 async init() { const [link, heading, beginning, choices, parts] = await Promise.all([ stored.storedLink, stored.storedHeading, stored.storedBeginning, stored.storedChoices, stored.storedParts, ]); this._data = { cloneLink: [...link], cloneHeading: [...heading], cloneBeginning: [...beginning], cloneChoices: [...choices], cloneParts: [...parts] }; }, // 获取克隆数据的方法,确保数据已初始化 getCloneData() { if (!this._data) { throw new Error('请先调用init()并等待异步操作完成'); } return { ...this._data }; // 返回副本避免外部修改原数据 } }; // 可选:模块加载时自动执行初始化 storyStore.init();
其他模块使用方式:
import { storyStore } from './你的模块路径.js'; async function useStoryData() { // 确保初始化完成(重复调用init不会重复执行) await storyStore.init(); const { cloneLink } = storyStore.getCloneData(); // 使用克隆后的数组 }
为什么之前的尝试没生效?
- 顶层await只能让模块加载等待异步操作,但如果直接导出原代码里的对象,对象的属性还是会在同步阶段初始化,无法等待Promise完成。
- 原代码中
cloneLink等属性在对象创建时就执行,此时sendToHell还没完全定义,直接触发了"Cannot access sendToHell before init"错误。 - 就算调用了
kamino(),异步操作完成前res还是空数组,克隆操作自然会失败。
内容的提问来源于stack exchange,提问作者Arnfinn Arend
相关产品推荐
相关产品推荐

