答应我在使用回调时返回待处理状态

2022-01-20 00:00:00 methods callback fetch javascript promise

我使用回调测试 fetch API,但我的函数返回Promise State: Pending",我不明白为什么:

异步函数 getJson(url, callback) {等待获取(网址).then(异步函数(响应){返回等待响应.json()}).then(函数(数据){控制台日志(数据)回调(数据)})}让 getData = {getAll:异步函数(){等待 getJson('js/getJson/data.json', function(data) {console.log(data.photographers)//OK让测试 = data.photographers返回测试})}}console.log(getData.getAll());//返回待处理的承诺

谢谢

解决方案

下面列出的异步和基于 Promise 编程的一般建议...

getJson() 应该是这样的:

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

只需返回 fetch() 已经返回的承诺 - 不要尝试转换为回调.将基于 Promise 的接口转换为回调接口在编程可用性方面是倒退的.Promise 比异步编程的普通回调要好得多.

getAll() 可以这样使用它:

const getData = {getAll:异步函数(){常量数据 = 等待 getJson('js/getJson/data.json');返回数据.摄影师;}}

或者,同样好(并且相当于上面的例子)是这样的:

const getData = {全部获取:函数(){return getJson('js/getJson/data.json').then(data => {返回数据.摄影师;});}}

await 在您对多个异步操作进行排序时具有显着优势,但在只有一个异步操作时通常并没有太大帮助.那样用也没有错,只是帮不上什么忙.

而且,这是调用 getAll() 的方式:

getData.getAll().then(photographers => {console.log(摄影师);}).catch(错误 => {控制台日志(错误);});

一般建议和说明:

1.阅读并研究 asyncawait 如何与 Promise 一起工作. 仅在您了解这一点后才使用它,然后您就只会使用 await 当你在等待一个承诺时.await 没有任何用处,除非您正在等待一个承诺,因此如果您正在等待一个函数调用,那么该函数必须返回一个承诺,并且该承诺必须连接到该函数中的异步操作时完成.

<强>2.不要混合使用普通回调和 Promise. 如果您正在使用 Promise 接口进行编程,请使用该 Promise - 切勿将其转换为普通回调.从您的函数返回一个承诺,并让调用者使用它.发明 Promise 的众多原因之一是非简单异步操作中的控制流在使用 Promise 时变得非常简单(尤其是异步错误处理和错误传播到更高级别).

3.将普通回调转换为 Promise. 如果您遇到想要在存在其他基于 Promise 的异步操作(例如 fetch())的世界中使用的异步操作,则 wrap普通回调到一个 Promise 接口,所以你只是混合了基于 Promise 的调用和其他基于 Promise 的调用.可靠地编写代码要简单得多.

4.async 函数总是返回一个 promise. 这就是它们在 Javascript 内部构建的方式.因此,async 函数的调用者总是会返回一个 Promise 作为返回值.该承诺最初将处于 pending 状态.它将在未来的某个时间被解析,并且最终解析的承诺值将是从 async 函数的外部范围返回的任何值.如果在 async 函数的外部范围内没有 return 语句,那么解析的值将是 undefined ,因为它与您的 `async功能.

5.调用者使用 .then()await 从 Promise 中获取已解析值. 这是从 Promise 中获取已解析值的仅有的两种方法.因此,任何想要从它返回一些值的 async 函数的调用者都需要使用 .then()await 来获取该值.

6.如果您在函数中有一个基于 Promise 的操作,并且您希望从您的函数返回它的解析值,那么只需从该函数返回该 Promise. 这将允许调用者使用该 Promise 来获取该值.请参阅上面的 getJson() 实现,了解它的简单程度.

7.避免使用 return await fn() 并改用 return fn(). 如果您使用的是 return await fn(),那么您已经在 async 函数中,因此该函数已经返回了一个承诺.因此,请避免使用额外的 await,因为它没有任何用处,只需使用 return fn().如果 fn() 返回一个值,该值将成为您的 async 函数返回的承诺的解析值.如果 fn() 返回一个 Promise,那么该 Promise 的已解析值将成为您的 async 函数返回的 Promise 的已解析值.

8.从 .then() 处理程序返回的值成为父 Promise 的解析值. 在上面的第二个 getData() 示例中使用 .then() 在内部,return data.photographers; 语句将父 Promise 的解析值设置为 data.photographers.因此,任何 getData() 的调用者都会发现 data.photographers 成为 getData() 返回的 promise 的解析值.p>

9.从 .then() 处理程序返回一个 Promise 将 Promise 链接起来,您返回的 Promise 的已解析值成为父 Promise 的已解析值. 本质上,从 .then() 处理程序返回一个 Promisecode>.then() 导致父 Promise 等待新返回的 Promise 解析,然后从新返回的 Promise 中获取其解析值.您可以在 getJson() 函数中看到这一点,其中 response.json() 返回一个新的 Promise,该 Promise 解析为 http 请求的 json 解析主体.该解析值将成为函数返回的承诺的解析值.

10.不要在期望返回承诺时传递回调.如果您将回调传递给某个异步函数,那么大多数时候该函数不会返回承诺,因为现在许多异步 API 接受回调或返回一个承诺,但不要同时做这两个.因此,在使用 await 时,请绝对确保您正在等待的函数正在返回一个 Promise.如有疑问,请查看文档.如果文档不清楚,请查看函数本身的代码或运行实验以查看实际返回值是什么.例如,如果您不向它们传递回调,大多数 mongodb 异步 API 将返回一个 Promise,但如果您传递回调,则不会返回一个 Promise.使用其中一种,不要同时使用.

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.

相关文章