0

AsyncWorker用来运行异步任务。问题是我有很多任务要一个接一个地运行,而且顺序很重要。为了保持秩序,我使用排队技术来确保AsyncWorker对象是按莱特顺序创建的,只有在每个任务完成后。我将回调存储在 avector<Function>中,并将其传递给AsyncWorker,但出现以下错误:

# Fatal error in v8::HandleScope::CreateHandle()
# Cannot create a handle without a HandleScope

还有其他方法可以解决这个问题吗?我也尝试过使用Napi::Persistent,但我无法将Napi::FunctionReference变量传递给AsyncWorker

调用者函数:

Napi::Value BlockChainWrapper::genesis(const Napi::CallbackInfo& info) {
    std::lock_guard<std::mutex> guard_ready_queue(ready_queue_mutex);
    this->ready_queue_callback.push_back(info[1].As<Napi::Function>());
    this->ready_queue_data.push_back(info[0].As<Napi::Object>());
    this->ready_queue_func.push_back(BlockChainWrapperTypes::_genesis_ready);
    this->ready_queue_env.push_back(info.Env());
    return info.Env().Undefined();
}
void BlockChainWrapper::genesis_ready() {
    AsyncBlockChainFunctions* asyncWorker = new AsyncBlockChainFunctions(this->ready_queue_callback.front(), 0, blockchain_obj, this->ready_queue_data.front());
    asyncWorker->Queue();
}

AsyncWorker 构造函数:

AsyncBlockChainFunctions::AsyncBlockChainFunctions(Napi::Function& callback, int mode, std::shared_ptr<BlockChain> _blockchain, Napi::Object& resource) : AsyncWorker(callback), mode(mode) {};

编辑 1 我实现了 PromiseWorker,但仍然遇到这些错误:BlockChainWrapper 继承 ObjectWrap。

Napi::Object BlockChainWrapper::Init(Napi::Env env, Napi::Object exports) {
    Napi::HandleScope scope(env);
    Napi::Function func = DefineClass(env, "BlockChainWrapper", {
        InstanceMethod("genesis", &BlockChainWrapper::genesis)
    });
    constructor = Napi::Persistent(func);
    constructor.SuppressDestruct();
    exports.Set("BlockChainWrapper", func);
    return exports;
}
# Fatal error in HandleScope::HandleScope
# Entering the V8 API without proper locking in place

修改 AsyncWorker 构造函数、类和解析函数:

class AsyncBlockChainFunctions : public PromiseWorker

AsyncBlockChainFunctions(Napi::Promise::Deferred const &d, std::shared_ptr<BlockChain> _blockchain, int mode, Napi::Object& resource) : PromiseWorker(d), mode(mode) {}

void Resolve(Napi::Promise::Deferred const &deferred) {
            deferred.Resolve(Napi::String::New(deferred.Env(), this->block_as_json_string));
};

调用函数:

Napi::Value BlockChainWrapper::genesis(const Napi::CallbackInfo& info) {
    std::lock_guard<std::mutex> guard_ready_queue(ready_queue_mutex);
    this->ready_queue_data.push_back(info[0].As<Napi::Object>());
    this->ready_queue_func.push_back(BlockChainWrapperTypes::_genesis_ready);
    this->ready_queue_env.push_back(info.Env());
    Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(info.Env());
    std::cout << "genesis" << std::endl;
    return deferred.Promise();
}

从另一个队列管理线程调用 Genesis 就绪

void BlockChainWrapper::genesis_ready() {
    Napi::Env env = ready_queue_env.front();
    Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(env);
    Napi::Object input_obj = this->ready_queue_data.front().As<Napi::Object>();
    auto *x = new AsyncBlockChainFunctions(std::ref(deferred), this->blockchain_obj, 0, input_obj);
    x->Queue();
}
4

2 回答 2

1

我不确定我是否正确理解了您或是否能够帮助您解决原来的问题,但您不应依赖AsyncWorker. 但是,您提到的错误听起来就像您构造AsyncWorker错误,即CallbackInfo可能有问题,即napi其所基于的环境。

承诺

但是,我强烈建议使用它AsyncWorker来处理我设计的生命周期,并切换到承诺模式。

基于https://github.com/nodejs/node-addon-api/issues/231#issuecomment-528986145

我建议您将其用作基类:

#include <napi.h>

class PromiseWorker : public Napi::AsyncWorker {
public:
    PromiseWorker(Napi::Promise::Deferred const &d) : AsyncWorker(get_fake_callback(d.Env()).Value()), deferred(d) {}

    virtual void Resolve(Napi::Promise::Deferred const &deferred) = 0;

    void OnOK() override {
        Resolve(deferred);
    }

    void OnError(Napi::Error const &error) override {
        deferred.Reject(error.Value());
    }

private:
    static Napi::Value noop(Napi::CallbackInfo const &info) {
        return info.Env().Undefined();
    }

    Napi::Reference<Napi::Function> const &get_fake_callback(Napi::Env const &env) {
        static Napi::Reference<Napi::Function> fake_callback
                = Napi::Reference<Napi::Function>::New(Napi::Function::New(env, noop), 1);
        fake_callback.SuppressDestruct();

        return fake_callback;
    }

    Napi::Promise::Deferred deferred;
};

然后,您将不得不对其进行子类化,覆盖Resolveand Execute,并将您需要的东西保存在您的成员私有中,然后您就完成了。

更新:我做了一个关于如何使用这个承诺的完整工作示例:https ://github.com/Superlokkus/spielwiese/tree/napi_promise_example

注意 Promise 方法:

#include <napi.h>

#include "promise_worker.hpp"

struct PromiseMethodWorker : PromiseWorker {
    PromiseMethodWorker(Napi::Promise::Deferred const &d, int input)
            : PromiseWorker(d), input_{std::move(input)} {}

    void Resolve(Napi::Promise::Deferred const &deferred) override {
        deferred.Resolve(create_js(deferred.Env()));
    }

    void Execute() override {
        output_ = input_ * 5;
    }

private:
    int input_;
    int output_;

    Napi::Number create_js(Napi::Env env) const {
        Napi::Number js_value = Napi::Number::New(env, output_);
        return js_value;
    }

};

Napi::Promise PromiseMethod(const Napi::CallbackInfo &info) {
    int input =  info[0].ToNumber();

    Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(info.Env());

    auto *wk = new PromiseMethodWorker(deferred, input);
    wk->Queue();

    return deferred.Promise();
}

使用方法和解决方案

所以你可以只使用 JS 中返回的承诺:

addon.PromiseMethod(42).then(value => add.PromiseMethod(value).then(...)) 

因此,您可以轻松地将这些 Promise 链接在一起,通过 Promise::all 等待所有。但是这样你就避免了所谓的回调地狱。但同样,您的分散订单要求对我来说听起来像是一个XY 问题

因此,与其将许多承诺/回调设为一个,不如说AsyncWorker似乎无法保证调用顺序。阻止一个承诺,可能会拖延一切。在您的本机代码中订购。

于 2020-03-13T11:08:01.407 回答
-1

以下内容甚至适用于数组

async.eachSeries(/*array*/, function(item, nextItem) {
    async.waterfall([
        function(callback) {
            //your logic
            callback(null, data);
        },
        function(data, callback) {
            //your logic
            callback(null, data2);  
        },
        function(data2, callback) {
            //your logic
            callback(null, 3); //The number is just for the argument purpose. Can be anything   
        }
        //You can continue adding as many steps as you want
    ],nextItem)         
});
于 2020-03-13T11:24:04.200 回答