You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript异步Promise填充Documentation对象异常问题求助

TypeScript异步请求填充数组问题修复方案

问题描述

我写了一段TypeScript代码,用来创建由文档路径和原始文本组成的Documentation对象列表。代码遍历CONFIG对象(键为章节名称,值为ConfigItem数组),收集文档路径及请求返回的Promise,随后调用Promise.all()尝试在所有数据就绪后一次性填充docs数组。

但运行时出现异常:浏览器控制台打印整个docs对象时能看到完整数据,紧接着遍历该对象却显示为空。我知晓这是get()请求返回Promise<Response>的异步特性导致的,但不知如何修复。相关代码如下:

const get = makeGetRequest('', 'application/text');
type Documentation = { path: string; rawText: string };
declare const CONFIG: Map<string, ConfigItem[]>;

/*
// from ConfigItem class
export interface ConfigItem {
    subItem: boolean;
    source: string;
}
// from seperate class
export declare const makeGetRequest: (apiUrl: string, dataType?: string) => (endpointUrl: string) => Promise<Response>;
*/

async function createDocs() {
    const docs: Documentation[] = [];

    const promises: { configItem: ConfigItem; promise: Promise<Response> }[] = [];

    CONFIG.forEach((value: ConfigItem[], key: string) => {
        value.forEach((configItem: ConfigItem) => {
            if (!configItem.subItem) {
                const promise = get(configItem.path);
                promises.push({ configItem, promise });
            }
        });
    });

    await Promise.all(promises).then(values => {
        values.forEach(entry => {
            const doc: Documentation = { path: '', rawText: '' };
            entry.promise
                .then(response => {
                    if (!response.ok) {
                        return Promise.reject(response);
                    } else {
                        return response.text().then(textValue => {
                            doc.path = entry.configItem.path;
                            doc.rawText = textValue;
                        });
                    }
                })
                .catch(e => Dialog.error('Failed to load page.', e));
            docs.push(doc);
        });
    });

    console.log('here is docs object');
    console.log(docs);

    (await docs).forEach(element => {
        console.log('element.name');
        console.log(element.name);
    });
}

问题分析

  1. 重复处理Promise:Promise.all(promises)已经会等待所有请求完成并返回结果,但你又在回调里重新调用entry.promise.then(),这不仅冗余,还导致填充doc的操作是在后续代码执行完之后才完成的。
  2. 提前推入空对象:你先把空的doc对象push进docs数组,之后才通过异步操作填充属性。遍历docs时,这些对象还没被填充,但浏览器控制台会实时更新对象的引用内容,所以你看到的是后续填充好的结果,遍历的时候却为空。
  3. 错误的await用法:最后(await docs).forEach完全错误,docs是普通数组,不是Promise,不需要await。

修复后的代码

const get = makeGetRequest('', 'application/text');
type Documentation = { path: string; rawText: string };
declare const CONFIG: Map<string, ConfigItem[]>;

/*
// from ConfigItem class
export interface ConfigItem {
    subItem: boolean;
    source: string;
}
// from seperate class
export declare const makeGetRequest: (apiUrl: string, dataType?: string) => (endpointUrl: string) => Promise<Response>;
*/

async function createDocs() {
    // 构建一个直接返回Documentation对象的Promise数组
    const docPromises: Promise<Documentation>[] = [];

    CONFIG.forEach((value: ConfigItem[]) => {
        value.forEach((configItem: ConfigItem) => {
            if (!configItem.subItem) {
                // 每个请求直接处理成Documentation对象的Promise
                const docPromise = get(configItem.path)
                    .then(response => {
                        if (!response.ok) {
                            throw response;
                        }
                        return response.text();
                    })
                    .then(textValue => ({
                        path: configItem.path,
                        rawText: textValue
                    }))
                    .catch(e => {
                        Dialog.error('Failed to load page.', e);
                        // 出错时可以返回一个空对象,或者根据需求处理
                        return { path: configItem.path, rawText: '' };
                    });
                docPromises.push(docPromise);
            }
        });
    });

    // 等待所有Promise完成,直接得到填充好的docs数组
    const docs = await Promise.all(docPromises);

    console.log('here is docs object');
    console.log(docs);

    // 直接遍历数组即可
    docs.forEach(element => {
        console.log('element.path');
        console.log(element.path);
        console.log('element.rawText');
        console.log(element.rawText);
    });
}

修复关键点

  • 直接构建目标Promise:让每个Promise直接返回Documentation对象,这样Promise.all之后就能直接得到完整的docs数组,不需要后续填充。
  • 移除冗余异步操作:不再重复处理已完成的Promise,避免异步逻辑嵌套导致的时序问题。
  • 简化异步代码:用async/await替代部分then嵌套,让逻辑更清晰易读。
  • 修正错误用法:去掉对普通数组的无效await,直接遍历已就绪的数组。

内容的提问来源于stack exchange,提问作者Barry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 11:25:29