简体   繁体   中英

Wait for variable in JavaScript

I'm using nodeJS. I want to wait for a property inside an object to become true, and then continue code execution.

Here's what my code looks:


export async function createRun() {
    try {
        let shared = { url: "", device: "", finished: new Promise(() => {}) };

        const browser = await launch();

        const page = await browser.newPage();

        await page.setDefaultNavigationTimeout(0);

        await page.setBypassCSP(true);

        await page.exposeFunction(
            "onMessageReceivedEvent",
            async (e: { type: string; data: Message }) => {
                if (e.data === "finished") {
                    shared.finished = ;
                }
            }
        );

        const listenFor = (type: string) => {
            return page.evaluateOnNewDocument((type: any) => {
                window.addEventListener(type, (e) => {
                    // @ts-ignore
                    window.onMessageReceivedEvent({ type, data: e.data });
                });
            }, type);
        };

        await listenFor("message");

       console.log('before');
       // wait for shared.finished to become true
       // continue execution
       console.log('after')
}

How can this be implemented? Thanks in advance!

Ok now having all details, it is possible to answer your question.

Getting the result thought an exposed function might - at first sight - prevent the usage of a Promise. But you can utilize closures for that.

So you create your callback function within a new Promise , and assign it to a variable outside of that. In your callback, you can resolve that promise when your condition e.data === "finished" is met.

        let onMessageReceivedEventCallback;
        const messageReceived = new Promise((resolve, reject) => {
          onMessageReceivedEventCallback = (e: { type: string; data: Message }) => {
              if (e.data === "finished") {
                  resolve();
              }
              // TODO you might want to reject in case an error occurs here, so that your application won't halt
          }
          // TODO if there is no specific error case then you might reject here after a given timeout
          // setTimout(() => reject(new Error("Timeout")), 1000);
        })

And you then pass that function to your page.exposeFunction , and later you use await messageReceived to wait for that promise to be resolved.

export async function createRun() {
    try {
        let shared = { url: "", device: "" };

        const browser = await launch();

        const page = await browser.newPage();

        await page.setDefaultNavigationTimeout(0);

        await page.setBypassCSP(true);

        
        let onMessageReceivedEventCallback;
        const messageReceived = new Promise((resolve, reject) => {
          onMessageReceivedEventCallback = (e: { type: string; data: Message }) => {
              if (e.data === "finished") {
                  resolve();
              }
              // TODO you might want to reject in case an error occurs here, so that your application won't halt
          }
          // TODO if there is no specific error case then you might reject here after a given timeout
          // setTimout(() => reject(new Error("Timeout")), 1000);
        })


        await page.exposeFunction(
            "onMessageReceivedEvent", onMessageReceivedEventCallback
        );

        const listenFor = (type: string) => {
            return page.evaluateOnNewDocument((type: any) => {
                window.addEventListener(type, (e) => {
                    // @ts-ignore
                    window.onMessageReceivedEvent({ type, data: e.data });
                });
            }, type);
        };

        await listenFor("message");

       console.log('before');
       await messageReceived;
       console.log('after')
}

To answer your original question, it is technically possible to achieve something like that using getter, setters, or Proxy. In the following, I show how something like that could be done using a Proxy. But please note that I highly discourage the usage of that. It just obscures what is going on in the code, and I can't imagine a use-case where this really makes sense.

 function createWaitAbleProperties(initialObject = {}, timeout = 2000) { function initProperty(obj, name) { obj.properties[name] = {} // utelizing a defere pattern which is not recommended // it is not as bas as the regular one due to the timeout but it is still bad obj.properties[name].promise = new Promise((resolve, reject) => { obj.properties[name].resolve = resolve setTimeout(() => reject(new Error('timeout for ' + name)), timeout); }) } return new Proxy(initialObject, { properties: {}, get: function(obj, prop) { let match; if (match = prop.match(/^(.*)Promise$/)) { if (!this.properties[match[1]]) { initProperty(this, match[1]) } return this.properties[match[1]].promise } else { return this.properties[prop]?.value } }, set: function(obj, prop, value) { if (!this.properties[prop]) { initProperty(this, prop) } this.properties[prop].resolve() this.properties[prop].value = value } }); } async function run() { const observer = createWaitAbleProperties() observer.value2 = 200 setTimeout(() => { observer.value1 = 100 }, 1000) await observer.value1Promise await observer.value2Promise console.log('finished', observer.value1, observer.value2) } run()

您需要一些设计模式,例如发布者 + 订阅者或观察者模式。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM