1

I have the following Javascript and I am trying to access the content data out of the service scope, what's the best way to access that data?

Service
.getContent()
.then((content = {}) => {//access this content out of 'Service' scope})
.catch((error = {})  => {console.log('errror', error)})

I tried the following:

let data = null;
Service
.getContent()
.then((content = {}) => {data = content})
.catch((error = {})  => {console.log('errror', error)})
console.log(data);

But I get the error that data is undefined. How can I get the contents of content to data

Arihant
  • 3,847
  • 16
  • 55
  • 86
  • Your console.log is outside of then(), so it will always be undefined. – Phix Apr 06 '18 at 17:55
  • @phix I do understand that, but can I return the data or something to access it outside? – Arihant Apr 06 '18 at 17:55
  • Make a getter inside your Service to access the data from outside. – GG. Apr 06 '18 at 17:56
  • 2
    You have to move your logging into the `then`, as @Phix mentioned. It's like passing a callback to a function; the code right after the promise chain will run _before_ the promise is resolved. – TrueWill Apr 06 '18 at 17:56
  • 1
    @Arihant promises and scopes are different things. can you use async/await? – uladzimir Apr 06 '18 at 17:56
  • 1
    I don't get your question. `Service` is a variable or a promise value, not a scope. – Bergi Apr 06 '18 at 17:58
  • @TrueWill. Since data is initialized with null, how can it throw an error or return undefined even though its logged outside then()? – Satish Kumar Apr 06 '18 at 18:04
  • @jfriend00 Thanks, sorry for the mixup. I'm trying to search for dupes on my phone but I can't think of the right search terms. – Andrew Li Apr 06 '18 at 18:35
  • @Li357 - Searching for dups here is hard. I regularly know there's a dup because I've seen it in the last week, but can't find it. – jfriend00 Apr 06 '18 at 18:36

1 Answers1

9

You can't do it this way. The issue is that a .then() handler is called at some indeterminate time in the future. It's always called at least on the next tick of the event loop (per the promise specification) and if there's a real asynchronous operation behind the promise, then who knows when it will be called (it could be ms to hours to never).

The ONLY way you can possibly know when it gets called and thus when a value provided in the .then() handler is available is by using the data it provides inside the .then() handler itself or by calling some function from within the .then() handler and passing the data to it.

Your console.log(data) statement always runs BEFORE the .then() handler is called. That's why you can't use the variable there. And, the only place you actually know when the data is available is inside the .then() handler so that's where you need to consume the data.

This is a different way of thinking about coding. It's the asynchronous model that Javascript uses for lots of things and you do need to learn it in order to be successful with Javascript.

So, the proper way to do things is this:

Service.getContent().then((content = {}) => {
    // use content here
    console.log(content);
}).catch(err => {
    // handle error here
    console.log('errror', err)
});

FYI, ES7 allows you to use await to make your code "look" a little more synchronous. It's important to understand how the actual asynchronous model works, even when using await. But, in your example, you could do this:

async function someFunction() {
    try {
        let content = await Service.getContent();
        // use content here
        console.log(content);
        return someValue;
    } catch(e) {
        // handle error here
        console.log('errror', err)
        return someOtherValue;
    }
}

someFunction().then(val => {
   // do something with val here
});

An important thing to understand is that while await appears to "block" the function execution until the promise resolves and makes it look like you can program synchronously again even with async operations, this is only partially true. The function execution itself is still asynchronous. In fact, as soon as you call await Service.getContent(), your function someFunction() returns a promise and any code after that function is called keeps on executing. So, the whole program flow is not blocked, only the internals of someFunction() are blocked waiting on that promise. await is really just syntactical sugar for .then(). The underlying concepts are still the same. And, functions still return immediately as soon as you await an asynchronous operation.

You can only use await inside an async function and all function declared async return a promise. So, the promise is still being used, await just gives you a bit more way to write code inside a function.

jfriend00
  • 683,504
  • 96
  • 985
  • 979