在上一篇文章中,我将queue理解为了队列,但其实在nodejs中,这只是业务名词,代表的是流程控制的一种方式,使用queue方式时,事件按照先进先出的准则执行。
queue
我们先了解一下事件的集中处理方式,参考文章。从这篇文章可以知道,nodejs提供了一个Async库,该库就是用来处理事件的。里面就有这一个queue。
在上一篇文章我们讲到了initQueue,我们这次再来看看:
Android.prototype.initQueue = function () {
this.queue = async.queue(function (task, cb) {
var action = task.action,
params = task.params;
this.cbForCurrentCmd = cb;
if (this.adb && !this.shuttingDown) {
this.uiautomator.sendAction(action, params, function (response) {
this.cbForCurrentCmd = null;
if (typeof cb === 'function') {
this.respond(response, cb);
}
}.bind(this));
} else {
this.cbForCurrentCmd = null;
var msg = "Tried to send command to non-existent Android device, " +
"maybe it shut down?";
if (this.shuttingDown) {
msg = "We're in the middle of shutting down the Android device, " +
"so your request won't be executed. Sorry!";
}
this.respond({
status: status.codes.UnknownError.code
, value: msg
}, cb);
}
}.bind(this), 1);
};
Async库中queue的定义一般如下所示:
var q = async.queue(function(task, callback) {
log(‘worker is processing task: ‘, task.name);
task.run(callback);
}, 1);
上面定义了一个工作线程为1的队列。当队列正在处理事件时,其他事件就一直等待。所以当我们使用queue的push方法时,queue会自己唤起然后执行,如果正在执行,push添加进来的事件会等到下一次执行。
uiautomator.sendAction
上面的请求,最终调用的是devices/android/uiautomator的sendAction的方法:
UiAutomator.prototype.sendAction = function (action, params, cb) {
if (typeof params === "function") {
cb = params;
params = {};
}
var extra = {action: action, params: params};
this.sendCommand('action', extra, cb);
};
然后转向sendCommand方法
uiautomator.sendCommand
UiAutomator.prototype.sendCommand = function (type, extra, cb) {
if (this.cmdCb !== null) {
logger.warn("Trying to run a command when one is already in progress. " +
"Will spin a bit and try again");
var start = Date.now();
var timeoutMs = 10000;
var intMs = 200;
var waitForCmdCbNull = function () {
if (this.cmdCb === null) {
this.sendCommand(type, extra, cb);
} else if ((Date.now() - start) < timeoutMs) {
setTimeout(waitForCmdCbNull, intMs);
} else {
cb(new Error("Never became able to push strings since a command " +
"was in process"));
}
}.bind(this);
waitForCmdCbNull();
} else if (this.socketClient) {
this.resendLastCommand = function () {
this.sendCommand(type, extra, cb);
}.bind(this);
if (typeof extra === "undefined" || extra === null) {
extra = {};
}
var cmd = {cmd: type};
cmd = _.extend(cmd, extra);
var cmdJson = JSON.stringify(cmd) + "\n";
this.cmdCb = cb;
var logCmd = cmdJson.trim();
if (logCmd.length > 1000) {
logCmd = logCmd.substr(0, 1000) + "...";
}
this.debug("Sending command to android: " + logCmd);
this.socketClient.write(cmdJson);
} else {
cb({
status: status.codes.UnknownError.code
, value: "Tried to send command to non-existent Android socket, " +
"maybe it's shutting down?"
});
}
};
最终会向设备端的socket发送一条命令,关于设备端接受命令以及如何处理,请查看我之前写的关于appium中bootstrap源码分析相关文章。
Done!