我是node.js的新手,而且我觉得我做错了什么,但是我有更难的时间用Google搜索好的答案,然后我出于某种原因使用其他语言。基本上我使用节点包装的c ++插件来做一些工作然后我想在我做了一些额外的解析之后通过websocket发送它。当同步完成额外的解析时,它会立即发送(如预期的那样)。当我在一个promise(这是第三方模块正在为我做的事情)中完成工作后,在调用resolve之后,需要花费相当长的时间来调用已完成的回调。喜欢超过5-10秒。这是代码:
var addon = require('...'); // Node wrapped C++ module
...
var server = http.createServer(){...};
var ios = io.listen(server);
function someFunction(args) {
console.log("Preparing to call some function");
someOtherFunction(args).then(funtction(val) {
console.log("Sending val over websocket....");
ios.sockets.emit('thing', val);
}
}
function someOtherFunction(args) {
return new Promise(function(resolve, reject) {
//logic
resolve(someVal);
console.log("Done with someOtherFunc");
}
}
ios.sockets.on('connection', function(socket){
console.log("Conneced");
// This does some work on a different thread. Eventually reposts to event loop and calls callback
addon.doThing("someVal", someFunc);
socket.on('disconnect', function() {
console.log("Disconnected");
});
});
输出:
Connected
Preparing to call some function...
Done with someOtherFunc;
<variable delay sometimes up to 5-10 seconds>
Sending val over websocket.
在第一次调用someOtherFunction之前,可能会对someFunction进行多次回调。这些都是发布到主Event循环的事件,所以我不相信任何东西都阻塞了。 输出:
Connected
Preparing to call some function...
Done with someOtherFunc;
<1 second delay>
Preparing to call some function...
Done with someOtherFunc;
<1 second delay>
Preparing to call some function...
Done with someOtherFunc;
<1 second delay>
<variable delay sometimes up to 5-10 seconds>
Sending val over websocket.
Sending val over websocket.
Sending val over websocket.
所以我的问题最初的想法是,当调用resolve时,立即调用回调。但这看起来并不像是在发生。有些事情正在触发回调最终触发,但我不知道它实际上是什么,它似乎是随机的。任何帮助将不胜感激!
C ++插件代码:
class NodeWrapper {
public:
static NodeWrapper& GetInstance() {
static NodeWrapper mInstance;
return mInstance;
}
~NodeWrapper() {
uv_close((uv_handle_t*) &mNodeAsyncEventLoop, NULL);
};
static void SendToNode(uv_async_t *handle) {
GetInstance().SendToNode();
}
void SendToNode() {
uv_mutex_lock(&mMutex);
swap(pushQueue, popQueue);
uv_mutex_unlock(&mMutex);
while(!popQueue.empty()) {
Data* pData = popQueue.front();
Isolate* isolate = Isolate::GetCurrent();
HandleScope scope(isolate);
const unsigned argc = 1;
Local<Value> argv = { node::Buffer::New(isolate, pData->mData, pData->mLen, DataDeleter, NULL).ToLocalChecked() };
Local<Function> cb = Local<Function>::New(isolate, mNodeCB);
cb->Call(isolate->GetCurrentContext()->Global(), argc, &argv);
popQueue.pop();
}
log << "Done with Callback!" << std::endl;
}
void SendOnData(const void* pData, DWORD dwLen) {
log << "Callback received!" << std::endl;
if(dwLen > 0) {
uv_mutex_lock(&mMutex);
pushQueue.push(new Data(pData, dwLen));
uv_mutex_unlock(&mMutex);
uv_async_send(&GetInstance().mNodeAsyncEventLoop);
}
};
static NodeWrapper mInstance;
UniquePersistent<Function> mNodeCB;
private:
NodeWrapper() {
uv_async_init(uv_default_loop(), &mNodeAsyncEventLoop, &NodeWrapper::SendToNode);
uv_mutex_init(&mMutex);
};
DATA_QUEUE pushQueue;
DATA_QUEUE popQueue;
uv_mutex_t mMutex;
uv_async_t mNodeAsyncEventLoop;
};
void doThing(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = Isolate::GetCurrent();
HandleScope scope(isolate);
auto f = std::bind(&NodeWrapper::SendOnData, &NodeWrapper::GetInstance());
DoThingAnotherThreadAndCallCallback(f);
NodeWrapper::GetInstance().mNodeCB = UniquePersistent<Function>(isolate, Local<Function>::Cast(args[1]));
}
输出更新:
22:01:57.831645 - Callback received
Preparing to call some function....
Done with someOtherFunc
22:01:57.839711 - Done with Callback!
22:01:57.918472 - Callback received
Preparing to call some function....
Done with someOtherFunc
22:01:57.927344 - Done with Callback!
Sending val over websocket....
Sending val over websocket....
答案 0 :(得分:1)
.then()
永远不会立即调用承诺resolve()
回调。相反,它们总是异步调用。无论是同步调用还是异步调用,都可以提供统一的异步行为,从而使调用者的生活更轻松。
Promise等到当前执行线程中的其他代码完成执行,并且堆栈帧已经清除回“平台代码”,如规范所述。然后,调用.then()
回调。如果你在那个执行线程中做了很多其他事情,那么在调用.then()
处理程序之前可能会有一段延迟。
答案 1 :(得分:0)
我通过从原生v8 Promises切换到bluebird Promises来解决它。本机v8 Promise由一个Microtask队列处理,我不确定如何处理c ++插件(我永远无法获得一个好的堆栈跟踪),但看起来微任务队列变得饥饿,直到它最终在一些事件之后运行冲了它(仍然不确定)。 bluebird使用SetImmediate,它立即处理,为我解决了问题。
进一步阅读:https://github.com/nodejs/node-v0.x-archive/issues/7714
这在v0.12中是“固定的”,我实际上是在使用io.js v3.2.0。我不是100%确定这是同一个问题还是不同。无论哪种方式,我现在都会坚持使用蓝鸟