打字稿 - 在函数返回之前等待承诺解决

Posted

技术标签:

【中文标题】打字稿 - 在函数返回之前等待承诺解决【英文标题】:Typescript - Wait for promise resolve before function return 【发布时间】:2018-09-29 02:50:19 【问题描述】:

更新了工作解决方案

我从一个函数开始,该函数从表中选择的所有行中获取信息,并将该信息推送到堆栈中以供以后处理。

for (var i = 0; i < this.selectedItems().length; i++) 
    var row = this.selectedItems()[i];
    let info = this.createFileReqInfo(row.Number(), FileRequestType.AssociatedDoc);
    fileReqInfo.push(info);

我的问题createFileReqInfo 函数在异步 API 调用返回值之前返回,所以我在返回对象中没有为 userCanView 获取正确的值。

createFileReqInfo = (reportId: number, fileRequestType: FileRequestType) : any => 
    let fileReq = new FileRequest(reportId, fileRequestType);
    var uCanView = false;
    this.reportModel.getReportSecurity(reportId).done((result) => 
        uCanView = result.CanViewReport;
        var info: 
            fileRequest: FileRequest,
            userCanView: boolean
         = 
            fileRequest: fileReq,
            userCanView: uCanView
        
        return info;        
    );

编译器不允许我在这里使用await。关于如何让函数在 API 调用返回之前阻塞的任何想法?


解决方案

我的问题是这里有几个级别的函数调用,我必须重新处理才能创建和解决 Promise。调用 API 的函数类似于建议的解决方案中的某些内容

createFileReqInfo = (reportId: number, fileRequestType: FileRequestType) : JQueryPromise<any> => 
    let fileReq = new FileRequest(reportId, fileRequestType);
    var uCanView = false;

    var info: 
        fileRequest: FileRequest,
        userCanView: boolean
     = 
        fileRequest: fileReq,
        userCanView: uCanView
    

    let dfd: JQueryDeferred<any> = $.Deferred();

    this.reportModel.getReportSecurity(reportId).done((result) => 
        uCanView = result.CanViewReport;
        info.userCanView = uCanView;
        dfd.resolve(info);
    );

    return dfd;

这现在返回一个承诺。我遇到的问题是调用这个函数的函数,因为它遍历选定项目的列表并将各种报告排队以下载,但仅限于该特定选择中存在的报告。必须使用this 回答找出一种方法来等待所有承诺解决后再继续。

getFileReqsFromSelectedItems = (view1: boolean, view2: boolean, view3: boolean): JQueryPromise<any> => 
    var fileReqInfo: 
        fileRequest: FileRequest,
        userCanView: boolean
    [] = [];

    let dfd: JQueryDeferred<any> = $.Deferred();

    let promise: JQueryPromise<any>;
    let promiseArray: JQueryPromise<any>[] = [];

    for (var i = 0; i < this.selectedItems().length; i++) 
        var row = this.selectedItems()[i];

        if( view1 && row.HasView1() ) 
            promise = this.createFileReqInfo(row.Number(), FileRequestType.AssociatedDoc1);
            promiseArray.push(promise);
        
        if( view2 && row.HasView2() ) 
            promise = this.createFileReqInfo(row.Number(), FileRequestType.AssociatedDoc2);
            promiseArray.push(promise);
        
        if( view3 && row.HasView3() ) 
            promise = this.createFileReqInfo(row.Number(), FileRequestType.AssociatedDoc3);
            promiseArray.push(promise);
        
    

    $.when.apply($, promiseArray).done(function() 
        var promises = arguments;
        for (var j = 0; j < promises.length; j++)
        
            fileReqInfo.push(promises[j]);
        
        dfd.resolve(fileReqInfo);
    );

    return dfd;

之后,很容易获取返回值数组并将其传递给下载函数。

downloadReports = () => 
    this.getFileReqsFromSelectedItems(this.view1Check(), this.view2Check(), this.view3Check()).then((fileReqsDetails) =>  
        this.downloadTrialFiles(fileReqsDetails);
    );

哇!

【问题讨论】:

出于好奇 - 您能否说明您是如何尝试使用 async/await 以及编译器错误是什么? 【参考方案1】:

您可以从 createFileReqInfo 返回 promise,然后等待它解决

for (var i = 0; i < this.selectedItems().length; i++) 
    var row = this.selectedItems()[i];
    let info = await this.createFileReqInfo(row.Number(), FileRequestType.AssociatedDoc);
    fileReqInfo.push(info);

或者

for (var i = 0; i < this.selectedItems().length; i++) 
    var row = this.selectedItems()[i];
    this.createFileReqInfo(row.Number(), FileRequestType.AssociatedDoc)
       .then(info => 
               fileReqInfo.push(info);
            );


其中createFileReqInfo定义为:

createFileReqInfo = (reportId: number, fileRequestType: FileRequestType) : Promise<any> => 
  return new Promise( (resolve, reject) => 
    let fileReq = new FileRequest(reportId, fileRequestType);
    var uCanView = false;
    this.reportModel.getReportSecurity(reportId).done((result) => 
        uCanView = result.CanViewReport;
        var info: 
            fileRequest: FileRequest,
            userCanView: boolean
         = 
            fileRequest: fileReq,
            userCanView: uCanView
        
        resolve(info);        
    );
    

【讨论】:

【参考方案2】:

对于不支持promise的API,你可以使用new Promise自己创建一个promise,用async调用的结果调用resolve,然后你可以在调用的时候使用async/await语法。 More info on promises

interface ReportSecurityInfo 
    fileRequest: FileRequest
    userCanView: boolean


createFileReqInfo = (reportId: number, fileRequestType: FileRequestType): Promise<any> => 
    let fileReq = new FileRequest(reportId, fileRequestType);
    var uCanView = false;

    return new Promise((resolve, reject) => 
        this.reportModel.getReportSecurity(reportId).done((result) => 
            uCanView = result.CanViewReport;
            var info: ReportSecurityInfo = 
                fileRequest: fileReq,
                userCanView: uCanView
            
            resolve(info)
        );
    )


// somewhere else...
const info = await this.createFileReqInfo()

为了便于阅读,我还继续将info 的类型拆分为自己的接口。

【讨论】:

这不就是把同样的问题推到堆栈上吗?我不能使用await 而不定义它作为async 出现的函数,这需要另一个承诺。 如果您正在使用的一个函数是异步的,那么它的所有调用者都必须是异步的,并且这些调用者的调用者等等。这就是 JS 中异步的工作原理。 这让我找到了完整答案的正确道路,但是,我必须努力解决这个问题。我将用我的最终解决方案更新原始问题。

以上是关于打字稿 - 在函数返回之前等待承诺解决的主要内容,如果未能解决你的问题,请参考以下文章

打字稿通用承诺返回类型

如何监视调用另一个返回承诺的服务的服务函数 - 打字稿

修改返回数据,然后在打字稿/离子中返回承诺

打字稿承诺泛型类型

承诺等待得到解决而不返回

函数缺少返回类型 - 在反应(打字稿)代码中