【问题标题】:Nodejs - libuv non-blocking event callbackNodejs - libuv 非阻塞事件回调
【发布时间】:2019-05-28 17:20:09
【问题描述】:

我正在尝试使用需要本机模块支持的 Node.Js 构建应用程序。我已经通过应用程序使用了 libuv 库,并且我能够使大多数异步方法工作,除了我必须实现进度事件回调的部分。我想异步实现进度事件回调,并且不阻塞 Node.js 事件循环。

这里是代码sn-ps:

native.cc

#include <node.h>
#include <uv.h>
#include "nbind/nbind.h"    

using v8::Isolate;
using v8::HandleScope;


int FileProgressCallback(uint64_t const sent, uint64_t const total, void const *const data) {
    nbind::cbFunction cb = *((nbind::cbFunction *) data);
    cb(sent, total);
    return 0;
}

class WorkerFileTransfer {
public:
    WorkerFileTransfer(std::string path, nbind::cbFunction cb) :
            callback(cb), path(path) {};

    uv_work_t worker;
    nbind::cbFunction callback;

    bool error;
    std::string errorMsg;

    std::string path;
};

void FileTransferDone(uv_work_t *order, int status) {
    Isolate *isolate = Isolate::GetCurrent();
    HandleScope handleScope(isolate);

    WorkerFileTransfer *work = static_cast< WorkerFileTransfer * >( order->data );

    if (work->error) {
        work->callback.call<void>(work->errorMsg.c_str(), work->output);
    } else {
        ThirdPartyLibraryFileCopy(work->path.c_str(), FileProgressCallback, (const void *) &work->callback);
    }

    // Memory cleanup
    work->callback.reset();
    delete work;
}

void FileTransferRunner(uv_work_t *order) {
    WorkerFileTransfer *work = static_cast< WorkerFileTransfer * >( order->data );

    try {
        work->output = true;
    }
    catch (...) {
        work->error = true;
        work->errorMsg = "Error occured while executing the method...";
    }
}

void FileTransfer(const std::string path, nbind::cbFunction &callback) {
    WorkerFileTransfer *work = new WorkerFileTransfer(path, callback);

    work->worker.data = work;
    work->path = path;
    work->error = false;

    uv_queue_work(uv_default_loop(), &work->worker, FileTransferRunner, FileTransferDone);
}

function(FileTransfer);

test.js

FileTransfer(
  '/path/file.txt',
  (sent, total) => {

    console.log(`sent`, sent);
    console.log('total', total);
  }
);

由于以下几行,我能够完成文件传输,但 Node.Js 事件循环在这里被阻塞。

void FileTransferDone(uv_work_t *order, int status) {
   ...

   ThirdPartyLibraryFileCopy(work->path.c_str(), FileProgressCallback, (const void *) &work->callback);

   ...
}

当我将行 ThirdPartyLibraryFileCopy(work-&gt;path.c_str(), FileProgressCallback, (const void *) &amp;work-&gt;callback); 移动到 FileTransferRunner(uv_work_t *order) 方法中时,我在 javascript 回调函数中没有得到任何输出。

如何在不阻塞 Node.Js 事件循环的情况下异步获取 javascript 回调函数中的进度值?

【问题讨论】:

  • 如果您错过了@saghul 的答案,有帮助吗?
  • @Can 我很高兴听到你想使用我的应用程序。由于我对 C++ 的了解有限,我无法解决此问题。如果有人有兴趣修复这个错误,请让我们把它拿出来。 github.com/ganeshrvel/openmtp/issues/8

标签: javascript c++ node.js libuv native-module


【解决方案1】:

根据uv_queue_work 文档:http://docs.libuv.org/en/v1.x/threadpool.html#c.uv_queue_work 工作回调(在您的情况下为FileTransferRunner)在线程池上运行,但完成回调(在您的情况下为FileTransferDone)在循环线程上运行。因此,如果对后者执行阻塞操作,就会阻塞循环。

如果您想发送定期进度报告,此模型不适合您。您可以使用异步句柄 uv_async_t 并使用工作函数中的 uv_async_send(这是线程安全的)报告进度。或者使用多个工作请求来发送块(这可能会更慢)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-11-07
    • 2012-08-17
    • 2015-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多