简体   繁体   中英

promise me return a pending state when I use a callback

I test the fetch API with a callback, but my function returns "Promise State: Pending", and I don't understand why:

async function getJson(url, callback) {
  await fetch(url)
    .then(async function(response) {
      return await response.json()
    })
    .then(function(data) {
      console.log(data)
      callback(data)
    })
}

let getData = {
  getAll: async function() {
    await getJson('js/getJson/data.json', function(data) {
      console.log(data.photographers) //OK
      let test = data.photographers
      return test

    })
  }
}

console.log(getData.getAll()); //return promise pending

Thanks

General advice for asynchronous and promise-based programming listed below...

Here's what getJson() should look like:

function getJson(url, callback) {
  return fetch(url).then(function(response) {
      return response.json();
  });
}

Just return the promise that fetch() already returned - don't try to convert to a callback. Converting a promise-based interface to a callback interface is going backwards in terms of programming usability. Promises are much better to program with than plain callbacks for asynchronous programming.

Here's how getAll() can then use it:

const getData = {
  getAll: async function() {
    const data = await getJson('js/getJson/data.json');
    return data.photographers;
  }
}

Or, equally good (and equivalent to the above example) would be this:

const getData = {
  getAll: function() {
    return getJson('js/getJson/data.json').then(data => {
        return data.photographers;
    });
  }
}

await has significant advantages when you are sequencing more than one asynchronous operation, but usually doesn't really help much when there's just one asynchronous operation. It's not wrong to use it then, it just doesn't really offer much help.

And, here's how one would call getAll() :

getData.getAll().then(photographers => {
    console.log(photographers);
}).catch(err => {
    console.log(err);
});

General Advice and Explanation:

1. Read and study how async and await work with promises. Only use it once you understand that and then you will only be using await when you are awaiting a promise. await does nothing useful unless you are awaiting a promise so if you're awaiting a function call, then that function must be returning a promise and that promise must be connected to when the asynchronous operations in that function are completed.

2. Don't mix plain callbacks and promises. If you are programming with a promise interface, use that promise - never convert it to a plain callback. Return a promise from your function and let the caller use that. Among the many, many reasons that promises were invented is that control flow in non-simple asynchronous operations is massively simpler with promises (particularly asynchronous error handling and error propagation to higher levels).

3. Convert plain callbacks to promises. If you encounter an asynchronous operation that you want to use in a world where there are other promise-based asynchronous operations (such as fetch() ), then wrap the plain callback into a promise interface so you are only mixing promise-based calls with other promise-based calls. Much, much simpler to code reliably.

4. async functions ALWAYS return a promise. That's how they are built internal to Javascript. So, a caller of an async function always gets back a promise as the return value. That promise will initially be in the pending state. It will be resolved sometime in the future and the eventual resolved value of the promise will be whatever value is returned from the outer scope of the async function. If there's no return statement in the outer scope of the async function, then the resolved value will be undefined as it is with both your `async functions.

5. A caller gets a resolved value from a promise with .then() or await . Those are the only two ways to get a resolved value out of a promise. So, any caller of an async function that wants some value back from it needs to use .then() or await to get that value.

6. If you have a promise-based operation inside a function and you wish to return it's resolved value from your function, then just return that promise from the function. That will allow the caller to use that promise to get the value. See my getJson() implementation above for how simple that can be.

7. Avoid return await fn() and use return fn() instead. If you're using return await fn() , then you're already in an async function and thus the function is already returning a promise. So, avoid the extra await as it doesn't do anything useful and just use return fn() . If fn() returns a value that value will become the resolved value of the promise that your async function returned. If fn() returns a promise, then the resolved value of that promise will become the resolved value of the promise that your async function returned.

8. Returning a value from a .then() handler becomes the resolved value of the parent promise. In the second getData() example above that uses .then() internally, the return data.photographers; statement sets the resolved value of the parent promise to data.photographers . So, any caller of getData() will find that data.photographers becomes the resolved value of the promise that getData() returns.

9. Returning a promise from a .then() handler chains the promises and the resolved value of the promise you return becomes the resolved value of the parent promise. Essentially, returning a promise from a .then() causes the parent promise to wait for the newly returned promise to resolve and it then gets its resolved value from that newly returned promise. You can see this in play in the getJson() function where response.json() returns a new promise that resolves to the json-parsed body of the http request.That resolved value will become the resolved value of the promise that the function returned.

10. Don't pass a callback when expecting a promise back. If you're passing a callback to some asynchronous function, then most of the time that function will not be returning a promise because many asynchronous APIs these days accept either a callback or return a promise, but don't do both at the same time. So, when looking to use await , make absolutely sure the function you're awaiting is returning a promise. When in doubt, look at the doc. If the doc is unclear look at the code for the function itself or run an experiment to see what the return value actually is. As an example, most of the mongodb asynchronous APIs will return a promise if you do NOT pass a callback to them, but will not return a promise if you do pass the callback. Use one or the other, not both.

It works, although it's not really what I wanted. Because I thought I could store my result outside of functions in a variable. But it seems that this is not possible in fact.

All this and due to the fact that I have to give an evaluation for my training. Fetch is not mandatory.

In the first version of my code, I didn't use it. I just did classes and function synchronously by loading my JSON into a variable and adding it to a script tag.

However, I wanted to do some tests because then I have to use the design pattern factory method. And I just tested and it works with your code. Thank you for taking the time to respond to me at such a late hour.


//we instantiate the factory
let factory = new identityFactory


     getData.getAll().then(photographers => {

        let identity = photographers
        console.log(identity);
        //we pass the identity in the factory
        let newIdentity = factory.createIdentity(identity,'all')
        console.log(newIdentity);
        showIdentity(newIdentity)

       
    }).catch(err => {
        console.log(err);
    });

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