How can I use a variable outside of the .then() scope

I have the following situation:

Why does the clients variable resolve in undefined when I call it below;

function getClientList() {
  TeamSpeak.connect({
    host: "localhost",
    serverport: 9987,
    nickname: "NodeJS Query Framework",
  }).then(async (teamspeak) => {
    const clients = await teamspeak.clientList({ clientType: 0 });

    if (clients) return clients;
    else return null;
  });
}

When I call it like that it resolves as undefined

const clients = getClientList();

The short answer to your question is that you cannot use a resulting variable until the Promise resolves. Whether you use .then or await it's really the same mechanism and you can't access the result of your call until it's ready.

You can only get the results of it by waiting for the Promise to resolve. This can be done by using await if your function is marked as async, or by using the .then() function on the Promise since it will get called after the result is ready.

Think of the Promise as a black box that has a then function in it. Remember that each .then() function also returns as a Promise object which is why you can chain them as promise.then(...).then(...).then(...);. Your code then looks like this:

function getClientList() {
  PROMISE1.then(someFunction);
}
const clients = getClientList();

Note that even though it spans multiple lines, your getClientList function is really just one line of code TeamSpeak.connect(...).then(...);

There are a few things wrong with your code. Let's go through them one by one:

  1. The getClientList function doesn't return anything explicitly. In its most basic form it's function getClientList() { someCall(); } and that returns undefined by default. That's why clients is always undefined.
  2. If you add a return statement to the function, it will return a Promise and might look like this:
function getClientList() {
  return PROMISE1.then(someFunction);
}
const clients = getClientList();

This is better because clients is not undefined any more, but it will be the Promise that may not have finished its work yet. To see the result of the call you'd need to use the then function like clients.then(result => console.log(result)) to allow it to wait for the asynchronous work to complete.

  1. You're using both .then and async/await. It will probably be cleaner and easier to work with if you go with one or the other (await is my preference). Your code can look like this:
async function getClientList() {
  const teamspeak = await TeamSpeak.connect({
    host: "localhost",
    serverport: 9987,
    nickname: "NodeJS Query Framework",
  });
  const clients = await teamspeak.clientList({ clientType: 0 });
  return clients || null;  // returns as a Promise resolving to clients or null
}
const clients = await getClientList(); // assuming you're in another async fn
  1. There is no error handling. If any of the asynchronous calls fail then the Promise will either reject or cause an exception. You should handle that by either surrounding it with a try/catch block at some level, or by adding .catch() after the final then, or by adding a second function to the .then() call to handle a rejection.

So putting it all together your code could look like this:

async function getClientList() {
  const teamspeak = await TeamSpeak.connect({
    host: "localhost",
    serverport: 9987,
    nickname: "NodeJS Query Framework",
  });
  return await teamspeak.clientList({ clientType: 0 }) || null;
}

// Example calling getClientList using ".then"
getClientList()
  .then(
    client => {
      /* use the client value in this scope */
    }, 
    reason => {/* report the reason for rejection */}
  )  // end of .then
  .catch(err => {/* report the error */});

// Example calling getClientList using "await"
try {
  const client = await getClientList();
  /* use the client value in this scope */
} catch (err) {/* report the error */}

No matter how you make the call, you're only able to access the clients value (returned by calling the clientList function) within the scope of either the .then or after await.