我正在使用以下代码,它工作正常,但问题是当我收到错误时,我希望它停止所有其他 promise 。例如,如果 chi.getCommand(val1, val2),将发送一个拒绝并且我得到了异常捕获,我想取消 chss.exe 和 app.getStatus(12); 我怎样才能做到这一点?
var start = Promise.all([
chi.getCommand(val1, val2),
chi.findAndUpdateCustomer()
]).spread(function (command, customer) {
return chss.exe(runnableDoc, command, customer)
.delay(10)
.then(function (val) {
if (val) console.log(val);
return app.getStatus(12);
});
}).catch(function (err) {
// catch and handle errors and when it come to here I want it to stops all the chain above
});
这是get命令的简写代码:
function getCommand(method, cmd) {
return new Promise(function (resolve, reject) {
...
child.stderr.on('data', function (data) {
console.log('stderr: here!' + data);
reject(data);
});
}
控制台日志 stderr: here! 被打印,所以解析被调用!
更新1
唯一停止 getStatus 的事情是当我放 process.exit(1) 但这会杀死所有进程,我只想停止函数 getCommand 的所有链,以防我到达捕获区,
- is there a way?
- is it bug in blueBird ? I use "bluebird": "2.9.34"
函数getCommand(方法,cmd){ return new Promise(function (resolve, reject) {
var spawn = require('child_process').spawn;
var ls = spawn("cmdbug",["/c","npm install express --save"]);
ls.on('error', function (err) {
console.log(err);
reject(err);
});
我得到的错误是
{ [Error: spawn cmdr ENOENT] code: 'ENOENT', errno: 'ENOENT', syscall: 'spawn cmdbug', path: 'cmdr', spawnargs: [ '/g', 'npm install express --save' ] } { [Error: spawn cmdbug ENOENT] code: 'ENOENT', errno: 'ENOENT', syscall: 'spawn cmdbug', path: 'cmdr', spawnargs: [ '/g', 'npm install express --save' ] } Child process failed with code -4058
getStatus 的进程仍在写入控制台。
我使用而不是用于测试的代码是:
getCommand 是引发错误的函数!
var start= function () {
return new Promise.all([
childP.getChildProcessCommand(val1, val2),
childP.findAndUpdateCustomer()
]).spread(function (cmd, updated) {
//Execute child process
return Promise.all([
childP.getCommand('spawn', cmd),
app.getStatus(51000,10,1);
]).catch(function (err) {
// catch and handle errors
console.log("An error occur: " + err);
return;
})
}).catch(function (err) {
// catch and handle errors
console.log("An error occur: " + err);
return;
})
}();
查询状态代码为:
// Returns a promise that resolves when the port is open
checkPortStatus: function(port, host){
return new Promise((resolve, reject) => {
portscanner.checkPortStatus(port, host, function(error, status) {
if(error)
reject(error);
else if(status === 'open')
resolve(status);
else
reject(new Error('Port is not open'));
});
});
},
// THE API function
getStatus: function(port, retriesLeft) {
const TIME_BETWEEN_CHECKS = 1000;
const HOST = '127.0.0.1';
const RETRIES = 20;
retriesLeft = retriesLeft === void 0 ? RETRIES : retriesLeft;
if(!port) throw new Error('Port is required');
if(retriesLeft === 0) Promise.reject('Timed Out');
return new Promise((resolve, reject) => {
// If it rejects, we do added work.
this.checkPortStatus(port, host).then(resolve, error => {
console.log("Waiting for port " + port + " attempt: " + retry);
setTimeout(() => {
this.getStatus(port, retriesLeft - 1).then(resolve, reject);
}, TIME_BETWEEN_CHECKS);
});
});
}
And I see the error in the console and still see the console log of the following for 10 attempts. console.log("Waiting for port " + port + " attempt: " + retry);
更新2 当尝试更改第二个选项中的@artur 建议时,我在递归调用中遇到错误,错误是:
TypeError: Cannot read property 'then' of undefined
这是我尝试过的:
getStatus: function(port, retriesLeft) {
const TIME_BETWEEN_CHECKS = 1000;
const HOST = '127.0.0.1';
const RETRIES = 20;
retriesLeft = retriesLeft === void 0 ? RETRIES : retriesLeft;
if(!port) throw new Error('Port is required');
if(retriesLeft === 0) Promise.reject('Timed Out');
var promise = new Promise((resolve, reject) => {
// If it rejects, we do added work.
this.checkPortStatus(port, host).then(resolve, error => {
console.log("Waiting for port " + port + " attempt: " + retry);
setTimeout(() => {
//The error in the following recursive call
this.getStatus(port, retriesLeft - 1).then(resolve, reject);
}, TIME_BETWEEN_CHECKS);
}).catch(function (error) {
return reject(error);
});
return {
promise:promise,
cancel: function() {
console.log('cancelling');
clearTimeout(token);
}
}
});
});
}
最佳答案
正如@Esailija 指出的那样,bluebird 具有内置的取消机制 - 这对于简单的异步计算来说非常好,并且肯定 完全没问题。
Promise.config({
cancellation: true
});
function createCancellableMock(result, time) {
return new Promise(function(resolve, reject, onCancel) {
// var child = runCommand();
var token = setTimeout(function() {
if (result) {
console.log('almost done', result);
resolve(result);
} else {
reject('_ERR_');
}
}, time);
onCancel(function() {
console.log('cancelling');
// child.kill('SIGTERM');
clearTimeout(token);
})
})
}
var op1 = createCancellableMock('ok-1', 1000);
//var op2 = createCancellableMock('ok-2', 500);
var op2 = createCancellableMock(null, 500); // will be rejected
Promise.all([op1, op2])
.spread(function(v1, v2) {
console.log('BOTH-OK', v1, v2)
})
.catch(function() {
console.error('ERROR');
op1.cancel();
})
.finally(function() {
console.log('finally');
})<script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/3.3.0/bluebird.core.js"></script>
您可以取消递归定义的操作(例如重试)。在这种情况下,最好的策略是不要用递归行为破坏 Action 本身。在下面的代码片段中,我创建了一个非常简单的包装器来说明我的观点。
var TOO_MANY_RETRIES_ERROR = 'too_many_retries_error';
var PROB_OF_FAIL = 0.8;
var INTERVAL = 200;
var RETRIES = 5;
var CANCEL_AFTER = null;
//var CANCEL_AFTER = INTERVAL * (RETRIES/2);
Promise.config({
cancellation: true
});
function retryWithCancel(params) {
// params = {op - operation to retry (it should return a promise, which either ),
// interval - between retries, retries - number of retries }
console.log('running, retries left ', params.retries);
params = Object.assign({}, params); // copy params - no side-effects please
params.retries--;
if (params.retries <= 0) {
console.error('too many retries');
return Promise.reject(new Error(TOO_MANY_RETRIES_ERROR));
}
return new Promise(function(resolve, reject, onCancel) {
var o = params.op()
.catch(function() {
return Promise.delay(params.interval)
.then(retryWithCancel.bind(null, params))
.catch(reject)
})
.then(resolve)
onCancel(function() {
console.log('Cancelling, retries left: ', params.retries);
o.cancel();
});
})
}
function fakeOperation() {
return Promise.delay(100)
.then(function() {
if (Math.random() > PROB_OF_FAIL) {
return Promise.resolve('SUCCESS');
} else {
return Promise.reject(new Error('ERROR'));
}
})
}
var p = retryWithCancel({
op: fakeOperation,
interval: INTERVAL,
retries: RETRIES
})
.then(console.log.bind(console))
.catch(console.error.bind(console))
.finally(console.log.bind(console, 'done'))
if (CANCEL_AFTER) {
setTimeout(function() {
p.cancel();
}, CANCEL_AFTER)
}<script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/3.3.1/bluebird.js"></script>
一般来说, promise 很棒,但它们不提供开箱即用的取消机制。在某些情况下(例如 https://github.com/whatwg/fetch/issues/27 )这是非常有问题的,并且在您的情况下,取消选项也非常方便。唯一有效的选择是自己添加。
我将问题提炼到最低限度,并使其可在浏览器中运行。
以下方法的缺点是取消后 promise 将永远不会 resolve 也不会 reject - 通常情况下肯定是 unacceptable .或者 .cancel 可能会用一些特殊符号拒绝 promise 。这两种方法似乎都不优雅。
function createCancellableMock(result, time) {
// child = null;
var token = null ;
var p = new Promise(function(resolve, reject) {
// child = runCommand();
token = setTimeout(function() {
if (result) {
console.log('almost done', result);
resolve(result);
}
else {
reject('_ERR_');
}
}, time);
}
)
return {
promise: p,
cancel: function() {
console.log('cancelling');
// child.kill('SIGTERM');
clearTimeout(token);
}
}
}
var op1 = createCancellableMock('ok-1', 1000);
// var op2 = createCancellableMock('ok-2', 500);
var op2 = createCancellableMock(null, 500); // will be rejected
Promise.all([op1.promise, op2.promise])
.then(function(vs) { // no spread in native implemantation
console.log('BOTH-OK', vs[0], vs[1])
})
.catch(function() {
console.error('ERROR');
op1.cancel();
})
对于基本的操作顺序,promise 是可以的,但有一种更优越的方法可用:即 observables。它们不仅提供内置的取消/处置机制,而且允许处理发出的多个值,并将复杂的异步执行保持在非常严格的控制之下。
function createCancellableMock(result, time) {
return Rx.Observable.create(function(observer) {
var done = false;
var token = setTimeout(function() {
if (result) {
console.log('almost done: ' + result);
observer.onNext(result);
observer.onCompleted();
} else {
observer.onError('_ERR_');
}
}, time);
// this will be called upon `disposed`
return function() {
console.log('disposing, done: ', done);
if (!done) {
clearTimeout(token);
}
}
})
}
var op1 = createCancellableMock('ok-1', 1000);
//var op2 = createCancellableMock('ok-2', 500);
var op2 = createCancellableMock(null, 500); // will be rejected
op1.zip(op2)
.catch(function(err) {
// it was disposed automatically :) hurray
console.log('Caught', err);
// return Rx.Observable.empty(); // swallowing
return Rx.Observable.throw(err); // throwing
})
.subscribe(function(vs) {
console.log('BOTH-OK', vs[0], vs[1])
},
function(err) {
console.error('Unhandled error', err);
},
function() {
console.log('Upon successful termination.')
}
);<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.7/rx.all.js"></script>
关于javascript - 在 Promise 被拒绝后停止运行进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35278729/
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/
exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby中使用两个参数异步运行exe吗?我已经尝试过ruby命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何rubygems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除
我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r
在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',
我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是
Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/
GivenIamadumbprogrammerandIamusingrspecandIamusingsporkandIwanttodebug...mmm...let'ssaaay,aspecforPhone.那么,我应该把“require'ruby-debug'”行放在哪里,以便在phone_spec.rb的特定点停止处理?(我所要求的只是一个大而粗的箭头,即使是一个有挑战性的程序员也能看到:-3)我已经尝试了很多位置,除非我没有正确测试它们,否则会发生一些奇怪的事情:在spec_helper.rb中的以下位置:require'rubygems'require'spork'
是否有可能:before_filter:authenticate_user!||:authenticate_admin! 最佳答案 before_filter:do_authenticationdefdo_authenticationauthenticate_user!||authenticate_admin!end 关于ruby-on-rails-before_filter运行多个方法,我们在StackOverflow上找到一个类似的问题: https://
之前在培训新生的时候,windows环境下配置opencv环境一直教的都是网上主流的vsstudio配置属性表,但是这个似乎对新生来说难度略高(虽然个人觉得完全是他们自己的问题),加之暑假之后对cmake实在是爱不释手,且这样配置确实十分简单(其实都不需要配置),故斗胆妄言vscode下配置CV之法。其实极为简单,图比较多所以很长。如果你看此文还配不好,你应该思考一下是不是自己的问题。闲话少说,直接开始。0.CMkae简介有的人到大二了都不知道cmake是什么,我不说是谁。CMake是一个开源免费并且跨平台的构建工具,可以用简单的语句来描述所有平台的编译过程。它能够根据当前所在平台输出对应的m