await 仅在异步函数中有效 - eval 在异步中
await is only valid in async function - eval in async
我想 eval() 异步函数中的一些代码行。虽然下面的代码没问题,
async function foo()
{
await foo1();
await foo2();
}
以下抛出错误:await is only valid in async function
let ctxScript = 'await foo1(); await foo2();';
async function foo()
{
eval( ctxScript );
}
我该如何处理?
我的 foo() 应该是异步的,因为它是 Puppetteer 控制器函数
foo()
不一定是 async
,因为它对 eval
的执行上下文没有影响。相反,一个可能的解决方案是将 ctxScript 包装在 self-executing 异步函数中,如下所示:eval("(async () => {" + ctxScript + "})()")
如果你想在一些更大的函数中动态调用一些异步代码,那么你可以提供一个回调来为你做这件事。这样你就可以通过给它不同的回调函数来执行不同的额外功能来调用你的函数:
// some sample async functions
var resolveAfter2Seconds = function() {
console.log("starting slow promise -> ");
return new Promise(resolve => {
setTimeout(function() {
resolve("slow");
console.log("<- slow promise is done");
}, 2000);
});
};
var resolveAfter1Second = function() {
console.log("starting fast promise ->");
return new Promise(resolve => {
setTimeout(function() {
resolve("fast");
console.log("<- fast promise is done");
}, 1000);
});
};
//a function that accepts a callback and would await its execution
async function foo(callback) {
console.log("-- some code --");
await callback();
console.log("-- some more code --");
}
//calling with an async function that combines any code you want to execute
foo(async () => {
await resolveAfter2Seconds();
await resolveAfter1Second();
})
最终使用了 Ermir 的答案:
let ctxScript = '(async () => {await foo1();await foo2();is_script_ended = true; })();';
async function foo()
{
// a lot of code
is_script_ended = false;
eval( ctxScript );
while(!is_script_ended){ await sleep(1000); }
// a lot of code
}
如果你想等待评估,你可以使用这个:
await Object.getPrototypeOf(async function() {}).constructor("your code here")();
这使用 AsyncFunction
构造函数。 MDN 有 a page on it 描述了使用它和使用 eval
:
之间的区别
Note: async functions created with the AsyncFunction constructor do not create closures to their creation contexts; they are always created in the global scope.
When running them, they will only be able to access their own local variables and global ones, not the ones from the scope in which the AsyncFunction constructor was called.
This is different from using eval with code for an async function expression.
这意味着如果您有希望评估代码能够访问的变量,则需要将它们添加到 globalThis
:
const testVar = "Hello world";
globalThis["testVar"] = testVar;
const result = await Object.getPrototypeOf(async function() {}).constructor(`
console.log(testVar);
await myAsyncFunc();
return testVar;
`)();
// result will be "Hello world"
delete globalThis["testVar"];
这是另一种不用睡觉或做任何复杂事情的方法。
在传递给 eval()
的代码中,将整个代码包装在另一个异步函数中并将其设置为某个变量,例如 EVAL_ASYNC
。然后在 运行ning eval(ctxScript)
、运行 之后那个异步函数 await EVAL_ASYNC
.
let ctxScript = 'var EVAL_ASYNC = async function() {await foo1(); await foo2();}';
async function foo()
{
eval( ctxScript );
await EVAL_ASYNC();
}
我想 eval() 异步函数中的一些代码行。虽然下面的代码没问题,
async function foo()
{
await foo1();
await foo2();
}
以下抛出错误:await is only valid in async function
let ctxScript = 'await foo1(); await foo2();';
async function foo()
{
eval( ctxScript );
}
我该如何处理? 我的 foo() 应该是异步的,因为它是 Puppetteer 控制器函数
foo()
不一定是 async
,因为它对 eval
的执行上下文没有影响。相反,一个可能的解决方案是将 ctxScript 包装在 self-executing 异步函数中,如下所示:eval("(async () => {" + ctxScript + "})()")
如果你想在一些更大的函数中动态调用一些异步代码,那么你可以提供一个回调来为你做这件事。这样你就可以通过给它不同的回调函数来执行不同的额外功能来调用你的函数:
// some sample async functions
var resolveAfter2Seconds = function() {
console.log("starting slow promise -> ");
return new Promise(resolve => {
setTimeout(function() {
resolve("slow");
console.log("<- slow promise is done");
}, 2000);
});
};
var resolveAfter1Second = function() {
console.log("starting fast promise ->");
return new Promise(resolve => {
setTimeout(function() {
resolve("fast");
console.log("<- fast promise is done");
}, 1000);
});
};
//a function that accepts a callback and would await its execution
async function foo(callback) {
console.log("-- some code --");
await callback();
console.log("-- some more code --");
}
//calling with an async function that combines any code you want to execute
foo(async () => {
await resolveAfter2Seconds();
await resolveAfter1Second();
})
最终使用了 Ermir 的答案:
let ctxScript = '(async () => {await foo1();await foo2();is_script_ended = true; })();';
async function foo()
{
// a lot of code
is_script_ended = false;
eval( ctxScript );
while(!is_script_ended){ await sleep(1000); }
// a lot of code
}
如果你想等待评估,你可以使用这个:
await Object.getPrototypeOf(async function() {}).constructor("your code here")();
这使用 AsyncFunction
构造函数。 MDN 有 a page on it 描述了使用它和使用 eval
:
Note: async functions created with the AsyncFunction constructor do not create closures to their creation contexts; they are always created in the global scope.
When running them, they will only be able to access their own local variables and global ones, not the ones from the scope in which the AsyncFunction constructor was called.
This is different from using eval with code for an async function expression.
这意味着如果您有希望评估代码能够访问的变量,则需要将它们添加到 globalThis
:
const testVar = "Hello world";
globalThis["testVar"] = testVar;
const result = await Object.getPrototypeOf(async function() {}).constructor(`
console.log(testVar);
await myAsyncFunc();
return testVar;
`)();
// result will be "Hello world"
delete globalThis["testVar"];
这是另一种不用睡觉或做任何复杂事情的方法。
在传递给 eval()
的代码中,将整个代码包装在另一个异步函数中并将其设置为某个变量,例如 EVAL_ASYNC
。然后在 运行ning eval(ctxScript)
、运行 之后那个异步函数 await EVAL_ASYNC
.
let ctxScript = 'var EVAL_ASYNC = async function() {await foo1(); await foo2();}';
async function foo()
{
eval( ctxScript );
await EVAL_ASYNC();
}