async function joinData()

in src/data/source.ts [114:161]


async function joinData(allData: UrlFetchedSource[]): Promise<AllPings> {
    const totalPings = allData.reduce((sum, d) => sum + d.data.crashid.length, 0);

    const pings = emptyPings(
        k => new IStringBuilder(totalPings, SIZE_HINTS[k]),
        () => new Array(totalPings),
    ) as Pings<IStringBuilder<string>, IStringBuilder<string | null>>;

    // Give the UI a chance to show status changes periodically.
    const showStatusChanges = () => new Promise(resolve => setTimeout(resolve, 0));

    let offset = 0;
    for (const { source, data } of allData) {
        source.setStatus({ message: "merging" });

        await showStatusChanges();

        // Populate the return data.
        for (const [field, desc] of pingFields()) {
            // Change indices as necessary.
            if (desc.type === PingFieldType.IndexedString) {
                const f = field as IndexedStringPingField;
                pings[f].addData(offset, data[f] as any);
            } else {
                const src = data[field] as any[];
                const dest = pings[field] as any[];
                for (let i = 0; i < src.length; i++) {
                    dest[offset + i] = src[i];
                }
            }
        }
        offset += data.crashid.length;

        source.setStatus({ success: true, message: `loaded ${data.crashid.length} pings` });
    }
    await showStatusChanges();

    // Build the IStringBuilders
    for (const [field, _] of pingFields().filter(([_, d]) => d.type === PingFieldType.IndexedString)) {
        const f = field as IndexedStringPingField;
        (pings as any)[f] = pings[f].build();
    }
    // XXX We don't currently use the minidump hashes, so clear them out to save memory.
    // They take up enough memory that we might consider dynamically fetching
    // them or truncating them.
    (pings.minidump_sha256_hash as any) = [];
    return pings as any;
}