在退出之前等待 KOAJS 中的 createWriteStream

Waiting for createWriteStream in KOAJS before exiting

我知道 this 问题,但我的需求有点不同。

我正在尝试下载多张图片,但无法阻止应用程序在该过程完成之前退出。我已经经历了很多次迭代,这就是我目前所在的位置:

router
.post('/', koaBody(), function *() {
    var images = [];
    //console.log(this.request.body.fields);
    if (this.request.body.fields) {
        images = this.request.body.fields['images'];
        imageCount = images.length;
    } else {
        this.status = 500;
        return;
    }

    var url = 'https://www.google.ca/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png';
    var filepath = '../images/image_1.png';

    var pipeRequest = function (url, filepath) {
        return new Promise(function (resolve, reject) {
            request.get(url)
                .pipe(fs.createWriteStream(filepath))
                .on('finish', function () {
                    console.log('piped');
                });
        });
    };

    co(function*() {
        yield pipeRequest(url, filepath);
    }).then(function () {
        console.log('done co-func');
    }).catch(function (err) {
        return console.error(err);
    });

    console.log('App exiting...');
});

这不是最优雅的代码,但它可以工作,如果我将辅助函数包装在一个循环中,我可以下载任意数量的文件(最终目标是让这个 API 收到一个 JSON 图片 URL 列表)。然而,我不能做的是 return 管道到调用者的结果,应用程序将始终在该过程完成之前退出。我认为将函数调用包装在 yield 中是答案......但不是。

当您在生成器函数(Koa 处理程序)中时,您使用 yield 等待。

一般模式是将您的异步逻辑提取到一个 return 承诺的函数中,然后在您的路由中产生它。

您的代码的第一个问题是您从未在将其转换为 finished/errored 状态的承诺中使用 rejectresolve。承诺永远不知道何时完成。屈服它永远不会 return 控制回路由,这可能是你将它嵌套在另一个 co 进程中的原因。

在这里,我修复了它,以便它在完成时 resolve()s,在错误时 reject(err)s。注意:产生命中 reject(err) 路径的承诺将抛出异常 (err),您可以在调用站点 try/catch。

var pipeRequest = function(url, filepath) {
  return new Promise(function(resolve, reject) {
    request.get(url)
      .pipe(fs.createWriteStream(filepath))
      .on('finish', function() { resolve() })
      .on('error', function(err) { reject(err) })
  });
};

我看到的第二个问题是您在路由中嵌套了一个 co 进程,这将确保路由永远不会等待其中的 yield

Koa 处理程序已经 运行 在 co 进程中。实施我上面的 resolve/reject 更改后,只需将整个 co 块替换为顶级 yield pipeRequest(url, filepath)