简体   繁体   中英

nodejs enable async function return value in global scope

I need to use a value returned by an asynchronous function into a get request. This is my code:

let pwd;

async function getSecret() {

    const [version] = await smClient.accessSecretVersion({
        name: pgpwd
    });
    const pwd = version.payload.data.toString();
    console.log(`in  ${pwd}`);
    return pwd;
}


  promise1 =  getSecret().then((pwd) => console.log(`promise then ${pwd}`)   );
  
  console.log(promise1.then((pwd) => console.log(`promise1 ${pwd}`)));
  
  console.log(`global scope pwd ${pwd}`);

app.get('/pwd', (req, res) => {
    console.log(`get ${pwd}`);
    res.send(`pwd = ${pwd}!`);
});

I receive the value in promise.then but it is undefined in the global scope.

2020-09-20 11:27:00.909  > node index.js
2020-09-20 11:27:00.909  
2020-09-20 11:27:02.152  GET200363 B2 sPostmanRuntime/7.26.5 https://nodejs1-
2020-09-20 11:27:03.379 get undefined
2020-09-20 11:27:03.445 in 123456
2020-09-20 11:27:03.445 promise then 123456
2020-09-20 11:27:03.445 promise1 undefined
2020-09-20 11:27:04.634 get undefined

You don't need a global variable at all. Make your GET request callback async as well and await the result of your getSecret function in the callback.

If getSecret is an expensive function to execute then you could wrap a function around it with a closure where the pwd value is stored in. Then when the function is called it checks if getSecret has been called before and calls it. Or when it has been called before just return the result instead of calling getSecret again.

async function getSecret() {
  const [ version ] = await smClient.accessSecretVersion({
    name: pgpwd
  });
  const pwd = version.payload.data.toString();
  return pwd;
}

function storePwd() {
  let pwd = null;
  return async function() {
    if (pwd === null) {
      pwd = await getSecret();
    }
    return pwd;
  };
}

const getPwd = storePwd();

app.get('/pwd', async (req, res) => {
  const pwd = await getPwd();
  res.send(`pwd = ${pwd}!`);
});

There is no magic to this. You just need to assign it:

let pwd; // global

// ...

getSecret().then((localPwd) => { // renamed to something different so that we
                                 // don't shadow (hide) the global pwd 
    console.log(`promise then ${localPwd}`);
    pwd = localPwd; // assign to global variable
})

That's it. It's just a variable assignment. Nothing more complicated than that.

Of course, doing it this way means that in the first few milliseconds when your app starts up before getSecret() returns the value of the global pwd is still undefined. And if you happen to do a get request at this time you will get undefined. But after that it will have the value you expect. As long as you are OK with this limitation I don't see anything wrong with what you are doing.

However, if you don't want your process to answer that get request then you must not define the get request until getSecret() returns. Normally I would personally write code like this:

getSecret().then((pwd) => {

    console.log(`promise then ${pwd}`);

    // ALL other app logic such as `get` definitions
    // are done inside the promise then:

    app.get('/pwd', (req, res) => {
        console.log(`get ${pwd}`);
        res.send(`pwd = ${pwd}!`);
    });
});

If you don't want the then function to be too long you can instead encapsulate your application logic in another function. This is nothing new, C/C++ has something like this with the main() function:

let pwd;

function init () {
    app.get('/pwd', (req, res) => {
        console.log(`get ${pwd}`);
        res.send(`pwd = ${pwd}!`);
    });
}

getSecret().then((localPwd) => {

    console.log(`promise then ${localPwd}`);

    pwd = localPwd;

    init(); // start the app
});

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