[英]Wait for variable in JavaScript
I'm using nodeJS.我正在使用 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.获得结果认为暴露的函数可能 - 乍一看 - 阻止使用 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.所以你在一个new Promise
创建你的回调函数,并将它分配给它之外的一个变量。 In your callback, you can resolve
that promise when your condition e.data === "finished"
is met.在您的回调中,您可以在满足条件e.data === "finished"
时resolve
该承诺。
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.然后您将该函数传递给您的page.exposeFunction
,然后您使用await messageReceived
等待该承诺得到解决。
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.要回答您最初的问题,在技术上可以使用 getter、setter 或 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()
您需要一些设计模式,例如发布者 + 订阅者或观察者模式。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.