JS 中的 api 调用是否需要等待结果?

发布于 2025-01-20 04:26:33 字数 1395 浏览 3 评论 0 原文

我在一个名为 userapi.js 的类中有以下端点:

const controller = 'User';
...
export async function getEmployeeInfo(employeeId) 
{
  const query = createQueryFromObject({employeId});
  const response = await get(`/${controller}/EmployeeInfo?${query}`);
  return retrieveResponseData(response, []);
}

这将从 usercontroller.cs 的后端中的操作方法中获取所需信息。

现在,说我想在 employeeview.vue 类中显示此信息,我必须再次等待它吗?为什么或为什么不呢?最初,我不会说不,您不会,因为您已经处理了等待/async userapi.js 类中resolve ?请解释。

  methods: {
    async setReportData(
     employeeId
    ) {
      this.isBusy = true;
      Promise.resolve(getEmployeeInfo(
        employeeId
      )).then((resultsEmployeeInfo) => {
        this.reportDatatableEmployeeInfo = resultsEmployeeInfo;
      })
        .catch(() => {
          this.alerts.error('An error has occurred while fetching the data');
        })
        .finally(() => {
          this.isBusy = false;
        });
    },

更新: ...

 * @param {Object} response
 * @param {any} defaultData
 * @param {Function} predicate
 * @returns {Promise}
 */
export function retrieveResponseData(response, defaultData = null, predicate = (predicateResponse) => predicateResponse) {
  const data = predicate(response) ? response.data : null;

  return data || defaultData;
}

I have the following endpoint in a class called UserApi.js:

const controller = 'User';
...
export async function getEmployeeInfo(employeeId) 
{
  const query = createQueryFromObject({employeId});
  const response = await get(`/${controller}/EmployeeInfo?${query}`);
  return retrieveResponseData(response, []);
}

This is going to get the required information from an action method in the backend of UserController.cs.

Now, say that I want to display this information in EmployeeView.vue class, do I have to await it again? Why or why not? Initially, I would say no, you don't, as you already dealt with the await/async in the UserApi.js class, but what about the Promise.resolve? Please explain.

  methods: {
    async setReportData(
     employeeId
    ) {
      this.isBusy = true;
      Promise.resolve(getEmployeeInfo(
        employeeId
      )).then((resultsEmployeeInfo) => {
        this.reportDatatableEmployeeInfo = resultsEmployeeInfo;
      })
        .catch(() => {
          this.alerts.error('An error has occurred while fetching the data');
        })
        .finally(() => {
          this.isBusy = false;
        });
    },

Update:
....

 * @param {Object} response
 * @param {any} defaultData
 * @param {Function} predicate
 * @returns {Promise}
 */
export function retrieveResponseData(response, defaultData = null, predicate = (predicateResponse) => predicateResponse) {
  const data = predicate(response) ? response.data : null;

  return data || defaultData;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

白云不回头 2025-01-27 04:26:33

您需要等待它,因为使用异步关键字 ALWAYS 声明的函数会返回 Promise,即使您只在其中执行同步操作,因此您需要等待或“thenize " 它来访问它解析到的值。这取决于异步函数的实现细节,异步函数只是产生承诺的生成器。

如果您担心这个问题,因为您在同步模块中工作并且不喜欢使用异步函数来执行更多异步函数,那么有一个好消息,TOP-LEVEL wait MODULES该提案处于第 4 阶段,因此很快就会随下一个 ECMA 版本一起发布。这样,您将能够在模块内部等待,就像它们被异步函数包装一样!
https://github.com/tc39/proposal-top-level-await

You need to await it since a function declared with async keyword ALWAYS returns a Promise, even if you do only synchronous stuff inside of it, hence you need to await or "thenize" it to access the value it resolved to. That depends from the implementation details of async functions which are just generators that yield promises.

If this concerns you because you work inside sync modules and don't like to use async functions just to execute more async functions, there's a good news, TOP-LEVEL await MODULES proposal is at stage 4, so it'll very soon be shipped with the next ECMA version. This way you will be able to await inside modules as if they were wrapped by async functions !
https://github.com/tc39/proposal-top-level-await

近箐 2025-01-27 04:26:33

我无法确定您是否需要再次等待它,因为我无法分辨 RECRIEVERESPONSEDATA 做什么。它可能会采用解决的价值并将其包裹在一个新的承诺中,然后需要 getemployeeeinfo 等待结果的呼叫者。

原因是:

诺言是围绕一个值

等待解开承诺的包装。 。然后。

就像现实世界中的礼物一样,一旦拆开了东西,您就无需再次将其解开。但是,对于我们来说非常方便的是,您仍然可以在未包装在承诺中的值上等待等待,它只会为您提供值。

您可以将任何价值包裹在承诺中,例如:

let wrappedFive = Promise.resolve(5)
//> wrappedFive is a Promise that must be unwrapped to access the 5 inside it

// this does _exactly_ the same thing as the above
let wrappedFive = new Promise(resolve => {
    resolve(5)
})

有时您最终会处于无法使用等待的情况下,因为您处于无法标记的 async < 。 /代码>。前端框架的生命周期方法(例如React(甚至可能是VUE))就是这样:该框架需要每个生命周期方法来完成其工作并立即完成。如果将生命周期方法标记为异步,则通常可以防止其具有预期效果。

在这种情况下,您通常需要使用链式

componentDidMount() {
    // this API call is triggered immediately by lifecycle,
    // but it basically starts a separate thread -- the rest
    // of this function does not wait for the call to finish
    API.getUserInfo()
    .then(userInfo => {
        // this happens after the API call finishes, but
        // componentDidMount has already finished, so what happens
        // in here cannot affect that function
        this.setState({ username: userInfo.username })
    })

    // this happens immediately after the API call is triggered,
    // even if the call takes 30 seconds
    return 5
}

。单独的线程 - 这些都发生在执行生命周期方法的相同线程中,即浏览器的渲染器线程。但是,如果您想到执行执行的编码器,那么您 not 的承诺基本上都会将叉子引入该codepath:立即遵循一条路径,并且每当承诺解决时,请遵循另一个路径。由于Browserland几乎是一个单线程的上下文,因此认为创造一个承诺作为单独的线程并不伤害您。这是一个细微差别,您可以忽略,直到您对JS中的异步图案感到满意。


更新: RECRIEVERESPONSEDATA do 似乎返回承诺。我可能是错的,如果预测返回承诺,但是如果那是真的,那么三元级将始终返回 wendesp.data ,因为未包装的承诺是真实的价值观(甚至 promise.resolve(false)是真实的)。

但是,任何调用 getemployeeInfo will 的人都必须等待它,因为该功能被标记为 async ,这意味着即使没有什么,即使没有什么,它也会返回承诺内部是异步的。考虑这个极端的例子:

// this function returns a number
function gimmeFive() {
    return 5
}

// this function returns a Promise wrapped around a number
async function gimmeFive() {
    return 5
}

I can't tell if you need to await it again, because I can't tell what retrieveResponseData does. It might take the resolved value and wrap it in a fresh promise, which would then require callers of getEmployeeInfo to await the result.

Here's the why:

A Promise is a wrapper around a value

await unwraps a Promise. So does the .then() handler you can register with a Promise (but the value is only unwrapped within the function you provide to .then()).

Just like a gift in the real world, once something has been unwrapped, you don't need to unwrap it again. However, very conveniently for us, you can still use await on a value that is not wrapped in a Promise, and it will just give you the value.

You can wrap any value in a Promise, like so:

let wrappedFive = Promise.resolve(5)
//> wrappedFive is a Promise that must be unwrapped to access the 5 inside it

// this does _exactly_ the same thing as the above
let wrappedFive = new Promise(resolve => {
    resolve(5)
})

Sometimes you end up in a situation where you can't use await, because you're in a function that cannot be marked async. The lifecycle methods of front-end frameworks like React (and possibly Vue) are like that: the framework needs each lifecycle method to do its job and be done immediately. If you mark the lifecycle method as async, you can often prevent it from having the intended effect.

In cases like that, you often need to use chained .then() handlers, which is a little uglier, but it works:

componentDidMount() {
    // this API call is triggered immediately by lifecycle,
    // but it basically starts a separate thread -- the rest
    // of this function does not wait for the call to finish
    API.getUserInfo()
    .then(userInfo => {
        // this happens after the API call finishes, but
        // componentDidMount has already finished, so what happens
        // in here cannot affect that function
        this.setState({ username: userInfo.username })
    })

    // this happens immediately after the API call is triggered,
    // even if the call takes 30 seconds
    return 5
}

Note that a Promise does not actually start a separate thread -- these all happen in the same thread that executes the lifecycle method, i.e. the browser's renderer thread. But if you think of the codepath that executes, a Promise that you don't wait for basically introduces a fork into that codepath: one path is followed immediately, and the other path is followed whenever the Promise resolves. Since browserland is pretty much a single-threaded context, it doesn't really hurt you to think of creating a Promise as spawning a separate thread. This is a nuance you can ignore until you are comfortable with asychronous patterns in JS.


Update: retrieveResponseData does not appear to return a Promise. I could be wrong, if predict returns a Promise, but if that were true, then the ternary would always return response.data because unwrapped Promises are truthy values (even Promise.resolve(false) is truthy).

However, anyone who calls getEmployeeInfo will have to wait it, because that function is marked async, and that means it returns a Promise even if nothing inside it is is asynchronous. Consider this extreme example:

// this function returns a number
function gimmeFive() {
    return 5
}

// this function returns a Promise wrapped around a number
async function gimmeFive() {
    return 5
}
波浪屿的海角声 2025-01-27 04:26:33

async函数 getemployeeInfo 等待 get 调用的结果,以返回呼叫返回的值 RECRIEVERESPONESPONESPONEDATATA

假设 get 也不是 reacrieveresponEdata 错误,则使用 geteMployeeeeInfo 的句法返回的值返回的值,用于解决通过调用 getEmployeeInfo 。

Promise.resolve 不需要将调用 getEmployeeeInfo 转换为承诺的结果,因为给定的异步函数返回返回承诺。

reacrieveresponsedata 是否返回承诺并不重要:标准async函数处理等待在调用异步函数时返回的承诺返回的承诺之前,请等待返回的承诺值。

异步函数 setrReportData 被声明为 async ,但使用链接的承诺处理程序方法编写以处理数据和错误条件的顺序 - 可以省略异步声明,但如果修改,则可能有用制作。

完成和提取的时候更新页面

setReportData( employeeId) {
  this.isBusy = true;
  getEmployeeInfo(
    employeeId
  ).then((resultsEmployeeInfo) => {
    this.reportDatatableEmployeeInfo = resultsEmployeeInfo;

    //  At this point the result in  this.reportDatatableEmployeeInfo can be used to update the page

  })
    .catch(() => {
      this.alerts.error('An error has occurred while fetching the data');
    })
    .finally(() => {
      this.isBusy = false;
    });
},

结果只能在获得数据 数据可用。插入更新页面的最简单的位置(在已发布的代码中)在然后在处理程序> setReportdata 内的处理程序函数中。


显示数据

已发布 setReportData 不会通过回调或通过返回承诺来通知其呼叫者。它所做的就是将结果保存在 this.reportDataTableEmployeeEinfo 和DIES中。

在不使用回调的情况下, setReportData 将带有两个选择

  1. 返回承诺,例如 Resulte EmployeeeeeInfo Undefined 如果一个错误发生:

      setReportData(雇员){
       this.isbusy = true;
    
       //返回最终承诺:
    
       返回getEmployeeInfo( 
           员工
         )
        。
           (this.ReportDataTableEmployeeEinfo = Results EmployeeInfo) 
         )
        .catch(()=&gt; {
           this.alerts.Error(“获取数据时发生了错误”);
           //返回未定义 
         }))
         .finally(()=&gt; {
           this.isbusy = false;
         });
     },,
     

    可以使用类似于

    的承诺在呼叫序列中使用的

      if(!this.busy){
       this.setReportData(someid)。然后(data =&gt; {
         如果(数据){
            //更新页面
         }
     }
     

    如果您想在异步上下文中拨打电话,则可以使用等待

      if(!this.busy){
       const data =等待this.setReportData(someid);
       如果(数据){
            //更新页面
       }
     }
     
  2. 在数据可用后,从 setReportdata 内部更新页面(如该数据可用时,如图所示,在此的第一部分中显示为注释回答)。该方法可能应从 setReportData 重命名为 getReportData 或类似以反映其目的。

Async function getEmployeeInfo awaits the result of the get call in order to return the value returned by a call to retrieveResponeData.

Assuming neither get nor retrieveResponeData errors, the value syntactically returned in the body of getEmployeeInfo is used to resolve the promise object actually returned by calling getEmployeeInfo.

Promise.resolve is not needed to convert the result of calling getEmployeeInfo into a promise because, given async functions return promises, it already is.

It doesn't matter if retrieveResponseData returns a promise or not: standard async function processing waits for a returned promise value to be settled before resolving the promise returned when calling the async function.

Async function setRreportData is declared as async but written using chained promise handler methods to process data and error conditions in order - the async declaration could be omitted, but may be useful if modifications are made.

The results can only be used to update the page at a time when the data has finished being obtained and extracted, shown as a comment in the following code:

setReportData( employeeId) {
  this.isBusy = true;
  getEmployeeInfo(
    employeeId
  ).then((resultsEmployeeInfo) => {
    this.reportDatatableEmployeeInfo = resultsEmployeeInfo;

    //  At this point the result in  this.reportDatatableEmployeeInfo can be used to update the page

  })
    .catch(() => {
      this.alerts.error('An error has occurred while fetching the data');
    })
    .finally(() => {
      this.isBusy = false;
    });
},

Displaying the data using EmployeeView.vue class must wait until the data is available. The simplest place to insert updating the page (in the posted code) is within the then handler function inside setReportData.


Displaying the data

As posted setReportData does not notify its caller of when report data is available, either by means of a callback or by returning a promise. All it does is save the result in this.reportDatatableEmployeeInfo and dies.

Without using callbacks, setReportData is left with two choices

  1. Return a promise that is fulfilled with, say,resultsEmployeeInfo or undefined if an error occurs:

     setReportData( employeeId) {
       this.isBusy = true;
    
       // return the final promise:
    
       return getEmployeeInfo( 
           employeeId
         )
        .then( (resultsEmployeeInfo) =>
           (this.reportDatatableEmployeeInfo = resultsEmployeeInfo) 
         )
        .catch(() => {
           this.alerts.error('An error has occurred while fetching the data');
           // return undefined 
         })
         .finally(() => {
           this.isBusy = false;
         });
     },
    

    which could be used in a calling sequence using promises similar to

     if(!this.busy) {
       this.setReportData(someId).then( data =>  {
         if( data) {
            // update page
         }
     }
    

    If you wanted to make the call in an async context you could use await:

     if(!this.busy) {
       const data = await this.setReportData(someId);
       if( data) {
            // update page
       }
     }
    
  2. Update the page from within setReportData after the data becomes available ( as shown as a comment in the first part of this answer). The method should probably be renamed from setReportData to getReportData or similar to reflect its purpose.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文