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

EdR*_*EdR 8 asynchronous typescript

更新了工作解决方案

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

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);
}
Run Code Online (Sandbox Code Playgroud)

我的问题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;        
    });
}
Run Code Online (Sandbox Code Playgroud)

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


解决方案

我的问题是这里有几个级别的函数调用,我必须重新创建和解决承诺。调用 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;
}
Run Code Online (Sandbox Code Playgroud)

这现在返回一个承诺。我遇到的问题是调用这个函数的函数,因为它遍历所选项目的列表并将各种报告排队下载,但只有那些存在于该特定选择中的报告。不得不使用答案找出一种方法,在继续之前等待所有承诺解决。

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;
}
Run Code Online (Sandbox Code Playgroud)

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

downloadReports = () => {
    this.getFileReqsFromSelectedItems(this.view1Check(), this.view2Check(), this.view3Check()).then((fileReqsDetails) => { 
        this.downloadTrialFiles(fileReqsDetails);
    });
}
Run Code Online (Sandbox Code Playgroud)

哇!

kin*_*aro 8

对于不支持promise的API,可以使用new Promise自己创建promise,resolve使用async调用的结果进行调用,调用时可以使用async/await语法。有关承诺的更多信息

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()
Run Code Online (Sandbox Code Playgroud)

我还继续将类型拆分info为它自己的界面以提高可读性。

  • 这不是把同样的问题推到堆栈上吗?如果不将它出现的函数定义为“async”,我就无法使用“await”,这将需要另一个承诺。 (2认同)