Home  >  Q&A  >  body text

How to write a more concise two-phase promise in JavaScript/TypeScript?

My use case here:

Is there a better design pattern?

let twoStagePromise = (state: boolean): Promise<{ ready: boolean, wait: Promise<any>; }> => {
    return new Promise((resolve, reject) => {
        try {
            if (state) {
                resolve({
                    ready: true,
                    wait: new Promise((resolve, reject) => {
                        resolve([1, 2, 3]);
                    })
                });
            } else {
                resolve({
                    ready: false,
                    wait: new Promise((resolve, reject) => {
                        setTimeout(() => { resolve([1, 2, 3]); }, 1000);
                    })
                });
            }
        } catch (e) {
            reject(e);
        }
    });
};

twoStagePromise(false).then((data) => {
    if (!data.ready) {
        console.log('loading...');
    }
    return data.wait;
}).then((result) => {
    console.log("recieved result", result);
}).catch((error) => {
    console.log("try-catch failed or inner promise failed")
});

After reading some comments, I simplified the code significantly:

let twoStagePromise = (state: boolean): Promise<number[] | Promise<number[]>> => {
    return new Promise((resolve, reject) => {
        try {
            if (state) {
                resolve([1, 2, 3]);
            } else {
                resolve(new Promise((resolve) => setTimeout(() => { resolve([1,2,3])  }, 1000)))
            }
        } catch (e) {
            reject(e);
        }
    });
};

twoStagePromise(false).then((dataOrPromise) => {
    if (dataOrPromise instanceof Promise) {
        console.log('loading...');
    }
    return dataOrPromise // continue the promise chain by returning the promise or data
}).then((result) => {
    console.log("recieved result", result);
}).catch((error) => {
    console.log("try-catch failed or inner promise failed", error)
});

P粉401527045P粉401527045236 days ago357

reply all(1)I'll reply

  • P粉270842688

    P粉2708426882024-02-26 18:30:07

    You can create a function that explicitly returns a value or its promise. You can easily await anyway. To check if the result is in sync, use result instanceof Promise

    type Awaitable = T | Promise
    function maybeImmediate(
        call: () => Awaitable,
        tryImmediate: boolean,
    ): Awaitable {
        if (tryImmediate) {
            try {
                return call(); // you don't know if it's T or Promise actually
            } catch (err) {
                //choose the one you want
                if (Math.random() > 0.5) {
                    throw err;
                } else {
                    return Promise.reject(err)
                }
            }
        } else {
            // make sure it's a promise
            return Promise.resolve().then(() => call())
        }
    };
    
    let cache: Record = {};
    function getCached(url: string): Awaitable {
        if (cache[url]) return cache[url];
        return new Promise(r => {
            setTimeout(() => r('result of ' url), 1000)
        }).then(v => { cache[url] = v; return v })
    }

    reply
    0
  • Cancelreply