You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript类链式异步方法嵌套await如何优化为简洁调用

解决方案

问题本质

你当前的Upload/CreateJob/GetJob都是async方法,调用后会直接返回Promise对象,但自定义的业务方法都定义在Transcribe类的原型上,Promise实例本身没有这些方法,所以才必须每一层都await拿回类实例,才能调用下一个方法,最终出现三层嵌套await的写法。
另外你类构造函数里写的this.Upload = this.Upload、this.CreateJob = this.CreateJob这类代码完全没有实际作用,可以直接删除。

改造方法

不需要在路由层写.then链式调用,也不需要嵌套await,只需要给类加内部异步队列,让每个业务方法调用时把逻辑排队、返回实例本身支持链式,再给类加thenable支持让整个链式调用可以被直接await即可。

改造后的AmazonS3基类

class AmazonS3 {
    constructor() {
        // 内部异步队列,初始为已完成状态的Promise
        this._chain = Promise.resolve();
    }

    Upload(file, bucket) {
        // 将上传逻辑追加到队列尾部
        this._chain = this._chain.then(async () => {
            const uploadParams = {
                Bucket: bucket,
                Body: fs.createReadStream(file.path),
                Key: file.filename,
            }
            this.data = await s3.upload(uploadParams).promise()
        })
        // 返回实例本身,支持链式调用
        return this
    }

    // 自定义then方法,符合thenable约定,支持直接await实例
    then(resolve, reject) {
        return this._chain
            .then(() => resolve(this.data))
            .catch(reject)
    }
}

改造后的Transcribe子类

class Transcribe extends AmazonS3 {
    CreateJob(params) {
        // 将创建转录任务逻辑追加到队列尾部
        this._chain = this._chain.then(async () => {
            if(this.data?.Location) {
                params.Media = { ...params.Media, MediaFileUri: this.data.Location }
            }
            this.data = await transcribeService.startTranscriptionJob(params).promise()
        })
        return this
    }

    GetJob(jobName) {
        // 将查询任务状态逻辑追加到队列尾部
        this._chain = this._chain.then(async () => {
            if(this.data?.TranscriptionJob?.TranscriptionJobName) {
                jobName = this.data.TranscriptionJob.TranscriptionJobName
            }
            this.data = await transcribeService.getTranscriptionJob({TranscriptionJobName: jobName}).promise()
        })
        return this
    }
}

改造后的路由代码

完全符合你预期的调用形式,只需要在最外层加一次await即可:

routes.post('/aws', upload.single('file'), async (req, res) => {
    const transcribeParams = JSON.parse(req.body.options)
    const bucket = 'bucket-name'

    const data = await awsTranscribe.Upload(req.file, bucket).CreateJob(transcribeParams).GetJob()

    res.send(data) 
})

注意事项

如果你的awsTranscribe是全局单例、会被多个请求复用,会出现异步队列串扰的问题(多个请求的操作排到同一个队列里),这种场景有两种解决方式:

  • 每次请求进来时新建一个Transcribe实例,用完即抛,是最稳妥的方案
  • 给类加一个重置方法,每次调用链开始前重置内部队列:
reset() {
    this._chain = Promise.resolve();
    this.data = null;
    return this
}

调用时先调reset即可:
const data = await awsTranscribe.reset().Upload(...).CreateJob(...).GetJob()


内容的提问来源于stack exchange,提问作者Nekit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 03:15:47