最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Dynamically create async function - Stack Overflow

programmeradmin2浏览0评论

I am wondering if it is possible to dynamically create an async function like this:

new Function('await Promise.resolve()');

Expectedly, the previous code throw:

Uncaught SyntaxError: await is only valid in async function

I am wondering if it is possible to dynamically create an async function like this:

new Function('await Promise.resolve()');

Expectedly, the previous code throw:

Uncaught SyntaxError: await is only valid in async function
Share Improve this question edited Dec 22, 2017 at 17:09 dda 6,2032 gold badges27 silver badges35 bronze badges asked Dec 22, 2017 at 17:08 Franck FreiburgerFranck Freiburger 28.4k21 gold badges73 silver badges97 bronze badges 4
  • 2 Of course it comes with the caveat that you should really never do this, but I think it's a very valid question :) – Luan Nico Commented Dec 22, 2017 at 17:17
  • Why would you need to create a function like that? – Kevin Jantzer Commented Dec 22, 2017 at 17:25
  • 5 You can always do new Function('return async function() { ... }')(). – Felix Kling Commented Dec 22, 2017 at 17:48
  • @FelixKling, you give the best solution, unfortunately I cannot accept a comment as answer – Franck Freiburger Commented Feb 23, 2018 at 13:33
Add a comment  | 

3 Answers 3

Reset to default 19

Yes, you can get a reference to the non-global AsyncFunction constructor to dynamically create async functions.

You get a reference to the AsyncFunction constructor like this:

const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;

The signature of the AsyncFunction constructor is:

AsyncFunction(arg0?, arg1?, ...args?, functionBody: string);

NOTE: The AsyncFunction contructor is not global (like Function is), the only way to get a reference to it is via the prototype of an async function(){} instance, as shown above and in the MDN docs.


Example 1. Simple function without parameters:

    const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
    
    const myAsync = new AsyncFunction(`return true`);
    
    const result = await myAsync(); // true
    
    myAsync().then((result) => {
        // result is true
    });

The example above is equivalent to:

    const myAsync = async () => {
        return true;
    };

Example 2. Defining parameters:

    const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
    
    // Define two named arguments: inValue, delay
    const asyncFn = new AsyncFunction('inValue', 'delay', `return new Promise((resolve) => {
        setTimeout(() => {resolve(inValue)}, delay);
    });`);
    
    // resolves to 'hello' after 100ms
    const result = await asyncFn('hello', 100);
    
    // After 200ms the promise will be resolved with the value 'world'
    asyncFn('world', 200).then((result) => {
        console.log(result);
    });

The example above is equivalent to:

    const asyncFn = async (inValue, delay) => {
        return new Promise((resolve) => {
            setTimeout(() => {resolve(inValue)}, delay);
        });
    };

Another cool thing is that the parameters are allowed to use defaults, destructuring, and rest parameters.

    const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
    
    // Define defaults for inValue and delay
    const asyncFn = new AsyncFunction('inValue = "Hello"', 'delay = 100', `return new Promise((resolve) => {
        setTimeout(() => {resolve(inValue)}, delay);
    });`);
    
    // resolves to 'hello' after 100ms (because we defined default parameters)
    const result = await asyncFn();
    
    // resolves to 'world' after 200ms
    const result = await asyncFn('world', 200);

Example 3. Higher-level function constructor

Just note that it might be insecure to construct a function like this if the delay value were to come from an untrusted source, like user input.

    const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
    
    function createAsync(delay){
        return new AsyncFunction('inValue', `return new Promise((resolve) => {
            setTimeout(() => {resolve(inValue)}, ${delay});
        });`);
    }
    
    const asyncFn = createAsync(100);
    const asyncFn2 = createAsync(200);
    
    // After 100ms this will resolve 'hello'
    await result1 = asyncFn('hello');
    
    // After 200ms this will resolve 'world'
    await result2 = asyncFn2('world');

This is roughly equivalent to:

    function createAsync(delay){
        return async (inValue) => {
            return new Promise((resolve) => {
                setTimeout(() => {resolve(inValue)}, delay);
            };
        };
    }
    
    const asyncFn = createAsync(100);
    
    // After 100ms this will resolve 'hello'
    await result1 = asyncFn('hello');
    
    // After 100ms this will resolve 'world'
    await result2 = asyncFn('world');

And remember that you can use await inside the dynamically created async function :)

Note that the same security considerations apply to the async function constructor as the Function constructor and eval().

If you are constructing a new function with content received from an untrusted source then your script or application may be vulnerable to injection attacks.

Don't use new Function(). I'd personally say NEVER use it unless you're a compiler because:

  1. It's ugly
  2. Code in strings is sooo 90s.. and it's ugly

Creating functions dynamically in js simply requires you to declare a function expression:

function functionMaker() {
    return function () {};
}

Therefore creating an async function dynamically is simply:

function asyncMaker() {
     return async function () {};
}

Use the new Function() syntax whit a return inside

async function foo() {
    return await new Promise(next => {
        setTimeout(()=> next('hello there!!'), 3000)
    })
}

var new_async = new Function(`return ${foo.toString()}`)()
console.log(new_async.toString())

发布评论

评论列表(0)

  1. 暂无评论