javascript - Väntar på ett löfte som jag skapade avslutar koden utan fel


Jag verifierade i konsolen att coordinator.setupPromise är ett Promise, men när jag kör await coordinator.setupPromise så når koden aldrig utskriftsstatements efter await och istället för att vänta avslutas den bara omedelbart. Exempel på konsoloutput:

tsx main.ts 
setup 
await setup Promise { <pending> }

Här är min kod:

import { ChildProcessWithoutNullStreams, spawn } from "child_process";
import { getPortFree, sleep } from "../utils";
import 'child_process'
import fetch, { RequestInit } from "node-fetch";
import { SocksProxyAgent } from "socks-proxy-agent";

class TorInstance {

    socksPort: number;
    controlPort: number;
    dataDir: string = `./datadirs/${Math.random().toString(36).slice(2)}`;

    torProcess: ChildProcessWithoutNullStreams;
    agent;
    setupRes;
    setupPromise = new Promise(res => { this.setupRes = res });

    constructor(socksPort?, controlPort?) {
        this.setup();
    }

    private async setup(socksPort?, controlPort?) {
        let port1 = await getPortFree();
        let port2 = await getPortFree();

        this.socksPort = socksPort ?? port1.port
        this.controlPort = controlPort ?? port2.port

        port1.server.close();
        port2.server.close();

        // tor --SocksPort 11111 --ControlPort 11112 --DataDirectory test1
        this.torProcess = spawn(`tor`, ['--SocksPort', this.socksPort, '--ControlPort', this.controlPort, '--DataDirectory', this.dataDir].map(String));
        this.torProcess.stdout.setEncoding('utf8');
        this.torProcess.stdout.on('data', (data) => {
            if (data.toString().includes(`[notice] Bootstrapped 100% (done): Done`)) { this.setupRes() }
        })
        this.agent = new SocksProxyAgent(`socks5h://127.0.0.1:${this.socksPort}`);
    }

    public fetch(url: string, options?: RequestInit) {
        return fetch(url, {
            ...options,
            agent: this.agent
        })
    }

    public dispose() {
        this.torProcess.kill();
    }


}

class TorCoordinator {
    instances: TorInstance[] = [];
    currentIndex = 0;
    setupRes;
    setupPromise = new Promise(res => { this.setupRes = res; })

    constructor(num: number) {
        this.createInstances(num);
    }

    fetch(url: string, options?: RequestInit) {
        return this.instances[this.currentIndex++].fetch(url, options);
    }

    createInstances(num) {
        let newInstances: TorInstance[] = [];
        for (let i = 0; i < num; i++) {
            let newInstance = new TorInstance();
            newInstances.push(newInstance);
            newInstance.setupPromise.then(() => {
                console.log('setup!!')
                this.instances.push(newInstance)
                this.setupRes();
            })
            // todo  monitor console output for [notice] Bootstrapped 100% (done): Done, and only add to main list then
        }
    }

}


async function test() {
    console.log('setup')
    let coordinator = new TorCoordinator(10);
    console.log('await setup',coordinator.setupPromise)

    await coordinator.setupPromise;
    console.log('done await')

    coordinator.fetch('https://api.ipify.org?format=json').then(res => res.text().then(console.log))
    coordinator.fetch('https://api.ipify.org?format=json').then(res => res.text().then(console.log))
    await sleep(10000)
}
test();

Och utils.ts är:

import { SocksProxyAgent } from "socks-proxy-agent"

export function sleep(m) { return new Promise(r => setTimeout(r, m)) }
export const torAgent = new SocksProxyAgent('socks5h://127.0.0.1:9050');


import { Readable } from 'stream';

export async function streamToBuffer(stream) {
    const chunks = [];

    for await (const chunk of stream) {
        chunks.push(chunk); // Collect each Uint8Array chunk
    }

    // Concatenate all chunks into a single Buffer
    const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);
    const buffer = Buffer.alloc(totalLength);
    let position = 0;

    for (const chunk of chunks) {
        buffer.set(chunk, position);
        position += chunk.length;
    }

    return buffer;
}


export async function streamToString(stream: ReadableStream) {
    const reader = stream.getReader()
    let html = ''
    while (true) {
        const { value, done } = await reader.read()
        if (value) {
            html += new TextDecoder().decode(value)
        }
        if (done) {
            return html
        }
    }
}

export async function streamToStringOld(stream: ReadableStream<Uint8Array<ArrayBufferLike>>) {
    const chunks: any = [];

    // Use async iteration to read from the stream
    for await (const chunk of stream) {
        chunks.push(chunk);  // Collect each Uint8Array chunk
    }

    // Concatenate all chunks into a single Uint8Array
    const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);
    const resultArray = new Uint8Array(totalLength);

    let position = 0;
    for (const chunk of chunks) {
        resultArray.set(chunk, position);
        position += chunk.length;
    }

    // Convert the Uint8Array to a string
    return new TextDecoder().decode(resultArray);
}

import net from "net"

export async function getPortFree():Promise<{port:number,server:net.Server}> {
    return new Promise( res => {
        const srv = net.createServer();
        srv.listen(0, () => {
            // @ts-ignore
            const port = srv.address().port
            res({port,server:srv});
            
        });
    })
}

Jag försökte vänta på ett löfte som jag hade skapat tidigare, men istället för att vänta på att passera till nästa rad, avslutas koden bara utan att något fel uppstår.

Svar #1

Din huvudfil väntar inte på test()-funktionen. Så när du kallar test() kan den bara avsluta när den är klar med att kalla på den funktionen.

Du borde prova detta istället

(async () => {
    await test();
})().catch(console.error);