Egg.js 控制器中有耗时操作,就无响应数据
发布于 1 个月前 作者 nobody 880 次浏览 来自 问答

现在在控制器中有段逻辑是写pdf文件,耗时约1秒多,加上此逻辑就无响应数据。 伪代码: class MyController { async logic(){ await createPdf() //这个耗时操作,注销掉就可正常返回数据. ctx.attachment(*.pdf); ctx.body={“success”}; } } @大神们,这种是否设计错误。请赐教

21 回复

没看懂你想问啥,await 不就是为了等待做完再返回么?如果耗时操作很占 CPU,甚至会影响其他请求的响应,这是可预期行为。

CPU密集型操作,直接fork一个子进程操作吧

@atian25 具体业务是这样的,在这个logic函数中中要生成一份pdf文件,然后打成zip包,给请求的用户下载到本地。现在遇到的问题是pdf文件及zip包都正常生成,但最终要response给用户的逻辑没执行,但也没报错。 class MyController { async logic(){ await createPdf() //这个耗时操作,注销掉就可正常返回数据. ctx.attachment(由createPdf()生成的zip文件名); ctx.body=fs.createReadStream(zip文件路径); } }

大概率是你 createPdf() 里面逻辑有问题,promise 一直没 resolve 了吧

@atian25 有resolve。有好多种文件导出并打包(除了pdf别的执行都时间都很短)都正常。就这个pdf出问题了。 开始运行创建PDF, 2020-12-21 13:29:46 开始执行: 1608529589161 执行完毕: 1608529590867 创建PDF结束, 2020-12-21 13:30:46 开始运行创建ZIP, 2020-12-21 13:30:46 添加zip文件2: 1608529589158 写入zip成功 创建ZIP结束, 2020-12-21 13:30:46 开始下载… 下载逻辑结束…

@atian25 下载逻辑就两行代码: ctx.attachment(fileName+".zip"); ctx.body=fs.createReadStream(“zip文件绝对路径”);

这不肯定是你的 createPdf() 函数出了问题,走了什么异常分支没有 resolve / reject 吧,框架不可能把你的逻辑吃掉的

所以很奇怪,这个控制器里好多生成文件然后压zip,都正常,就这个pdf

生成文件不代表createPdf 函数执行完了,createPdf函数贴出来看看

@nobody 有可能这个pdf太大了或别的什么原因,导致出错了,但是你没写try catch

@iori2882 我加个try catch试试

@chenkai0520 使用的是html-pdf pdf.create(htmlStr, { format: ‘A4’ }).toStream(function(err, stream){ stream.pipe(fs.createWriteStream(filePath)); if(err){ reject(err) }else{ console.log(‘执行完毕:’,Date.now()) resolve() } })

@nobody pipe不是一个同步函数,resolve的时候文件还没有生成呢

@chenkai0520 好的,我再试试

@iori2882 加入try catch 没抓到任何错误。

@nobody 从上面那段代码看出,你对 Promise 和 Stream 这块的理解需要再复习下。

// 餐厅点菜
async logic(){ 
   stream.pipe(fs.createWriteStream(filePath));  // 服务员通知厨师做菜,厨师说:好嘞,差不多 5 分钟搞定。
   resolve() // 通知后 1 毫秒立刻告诉用户:这是你的菜,做好了。(厨师:『???』
   ctx.body=fs.createReadStream(zip文件路径); // 用户对着空气吃菜,收获『???』
}

@atian25 还有

  • err的判断应该放到开始位置
  • 没有判断pipe函数是不是执行成功了或失败了

@atian25 已经解决了,忘记回来回复一下。谢谢大佬百忙之中给出通俗易懂的解释

@chenkai0520 多谢大佬点拨

stream.pipeline 这个新方法可以关注下

回到顶部