I'm developing a Node.js app and I'm using Vorpal commands. I'm trying to send a value from the command to a function but i can't get it to work. Am I doing anything wrong?
Here is the code:
vorpal
.command('rollto <num>', 'Rolls to')
.action(function(num) {
rollto(num);
});
function rollto(num) {
bettime = bettimems % 60;
socket.emit('betting', bettime);
timer1 = setInterval(function () {
bettime--;
socket.emit('betting', bettime);
if (bettime == 0) {
socket.emit('random number', num);
console.log("Rolled to:" + num + "!!!");
clearInterval(timer1);
}
}, 1000);
}
The problem is that the function you pass to command's action has different arguments than you assume.
Here is the relevant part from docs:
.command.action(function)
This is the action execution function of a given command.
It passes in an arguments object and callback.
Actions are executed async and must either call the passed
callback upon completion or return a Promise.
And here is a working example:
var vorpal = require('vorpal')();
vorpal
.command('rollto <num>', 'Rolls to')
.action(function(arguments, callback) {
rollto(arguments, callback);
});
function rollto(arguments, callback) {
var num = arguments.num; // get 'num' parameter from arguments
timer1 = setInterval(function () {
console.log('test');
console.log(num);
clearInterval(timer1);
callback(); // Don't forget to use callback() to notify vorpal
}, 1000);
}
vorpal
.delimiter('myapp$')
.show();
Note that you actually have an async code inside setInterval, so you need to use callback() at the end to notify vorpal that processing is finished.
Related
I'm trying to solve this async problem. I got the problem working.
However, after calling "done" callback it's throwing an error. I don't know why.
Issue:
I want to print the task number once "Done" is invoked.
But it throws an
error saying TypeError: "callback" argument must be a function
Problem:
A "TaskRunner" Constructor takes one argument, "concurrency", and
exposes one method "push" on its prototype. The "push" method takes
one argument "task" which is a "function"
Passing a task to a push method of a TaskRunner instance should
immediately execute (call/run/invoke) the task, unless the number
of currently running tasks exceeds the concurrency limit.
function TaskRunner(concurrency) {
this.count = concurrency;
this.queue = [];
}
TaskRunner.prototype.push = function(task) {
if (this.count === 0) {
this.queue.push(task);
} else {
this.invoke(task);
}
}
TaskRunner.prototype.invoke = function(task) {
task.call(null, this.done.bind(this));
this.count--;
}
TaskRunner.prototype.done = function(num) {
console.log(`After Executing done: ${num}`)
this.count++;
this.execute();
}
TaskRunner.prototype.execute = function() {
if (this.queue.length > 0) {
var task = this.queue.shift();
this.invoke(task);
}
}
function factory(num) {
return function exampleSimpleTask(done) {
this.num = num;
console.log("task", "Before " + new Date().getTime());
setTimeout(done(num), 2000);
}
}
var r = new TaskRunner(2);
r.push(factory(1));
r.push(factory(2));
r.push(factory(3));
EDIT: For some reason, on jsfiddle it runs fine but when I run the same code on my local it fails.
Please help.
You are passing the setTimeout the result of you function:
setTimeout(done(num), 2000);
This will call done(num) immediately and setTimeout will try to call whatever done() returned as through it were a function.
You should pass it a function that it can call instead:
setTimeout(() => done(num), 2000);
or [as #JaromandaX points out in the comment] you can take advantage of the options third argument of setTimeOut which will be passed into the callback function:
setTimeout(done, 2000, num);
this will call the function done and pass in num
I'm assigning to a variable, a function that uses setInterval, but I don't want the function to run until I call it. However, the function is running from just the assignment statement.
sessionClock = setInterval(function() {
console.log("Hi")
}, 1000)
I have also tried like this:
sayHi = function() {
console.log("Hi");
}
var sayHiStarter = setInterval(sayHi, 1000);
Both of these initiate the function and will log "Hi" to the console.
Why is it running on assignment? And what can do I do fix this?
If you only want to bind a function to setInterval, but call it later, you can use bind:
var sessionClock = setInterval.bind(null, function() {
console.log("Hi")
}, 1000);
//... later
var myInterval = sessionClock(); // start the timer
// ... later if you need to clear it
clearInterval(myInterval);
In principle, bind returns a new function that calls your original function (in this case, setInterval) with predefined arguments. So when you call sessionClock, that returned function is called. There a other aspects to bind, but they don't seem to apply in this context.
The call to setInterval does not return a function, but an identification for the created interval. This id is used to remove the interval when you don't want it to execute anymore:
sessionClock = setInterval(function() {
console.log("Hi")
}, 1000)
...
clearInterval(sessionclock);
What you want is something like this:
sessionClock = function () {
return setInterval(function() {
console.log("Hi")
},
1000);
}
//When needed
var intervalId=sessionClock();
I want to run func2 run only after func1 has finished.
{
func1();
func2();//
}
But when func1() starts, func2() does not wait for func1() to get finished. func2() run simultaneously with func1(), which causes run time error, because func2() need some input from func1().
I also tried using async module, but got no success.
Edit: I run the function check(), which call two functions prompt() and copyProject(). copyProject() should run only after prompt() function has finished, but it start executing simultaneously.
var check = function check (){
async.series([
function(callback){
prompt();
callback(null);
},
function(callback){
copyProject();
callback(null);
}
]);
};
var prompt = function prompt(){
var prompts = [{
name: "projectName",
message: "What is the name of your project?"
},{
name: "authorName",
message: "What is your name?",
}];
inquirer.prompt(prompts, function( answers ) {
for (var key in answers) {
if (answers.hasOwnProperty(key)) {
console.log(key + " -> " + answers[key]);
infoToRender[key] = answers[key]
}
}
});
};
var copyProject = function copyProject (){
// code to copy some files from one location to another based on input from prompt function
};
Your function prompt is itself an asynchronous function: The call to inquirer.prompts causes the function to wait and this makes it asynchronous. Since your prompt function does not use a callback, the async module can not know when prompt has finished: In contrast, it runs prompt and this function immediately returns. Hence async right afterwards runs copyProject.
What you need to do to solve this issue is to introduce a callback function in prompt that async "waits" for. So basically something like this:
var prompt = function (callback) {
// Do your stuff here...
inquirer.prompt(prompts, function (answers) {
// Your for loop here...
callback(null);
});
};
Then, within async you need to do:
async.series([
function (callback) {
prompt(callback);
},
function (callback) {
copyProject();
callback(null);
}
]);
Then copyProject is only run when prompt has been completed. Please note that async.series will not wait for copyProject to finish, in case this is an asynchronous function, as again, it does not take a callback. So same pattern applies here.
This question already has answers here:
How can I pass a parameter to a setTimeout() callback?
(29 answers)
Closed 12 months ago.
function f1()
{
c = setTimeout(f2,200);
}
function f2()
{
//code
}
The above code is just fine. But what I want to ask that: can I use some argument in function f2() which is passed from the calling environment? That is:
function f1(v1)
{
c = setTimeout(f2(v1),200);
}
function f2(v2)
{
//code
}
Is it valid? Because I tried something like this,but the problem is that I am not able to clearTimeout by using variable c. I am not sure what to do.
Use Closure -
function f1(v1)
{
c = setTimeout(f2(v1), 200);
}
function f2(v2)
{
return function () {
// use v2 here, and put the rest of your
// callback code here.
}
}
This way you will be able to pass as many arguments as you want.
Since you are declaring c as a global variable (which is bad), you can easily clear the timeout using -
clearTimeout(c);
If you are still not being able to clear the timeout, it only means that the duration has elapsed and your callback fired, or there is some error somewhere else. In that case, post your code that you are using to clear your timeout.
You can either use the function.bind method or you can simply wrap the invocation
function f1(v1) {
c = setTimeout(function() {
f2(v1);
}, 200);
}
var timeout;
// Call `f2` with all arguments that was passed to the `f1`
function f1 () {
var args = arguments;
timeout = setTimeout(function () { f2.apply(this, args) }, 200);
}
Or in this way:
// Call `f2` with some params from `f1`
function f1 (v1) {
timeout = setTimeout(function () { f2(v1) }, 200);
}
Answer to your question: you couldn't clear the timeout because you execute function immediately.
Ok. here's the scenario:
function DataFeed(){
function PopulateData()
{
$('div#example').load('http://www.example.com', fxnCallBack);
};
function fxnCallBack()
{
PopulateData();
}
this.activator = function() {
PopulateData();
}
};
var example_obj = new DataFeed;
example_obj.activator();
In the above code, the ajax .load gets executed once, then callback executes. But the callback doesn't start the ajax function again?
Thanks in advance.
edit- why doesn't it display new line properly -.-
InternalError: too much recursion
JavaScript engines normally have a max limit in the number of recursions or the time recursive execution may take. Use setInterval instead:
function DataFeed() {
var interval;
function PopulateData() {
$('div#example').load('http://www.example.com', function(data) {
if(data == "clear_interval")
interval = clearInterval(interval); // clear the interval
});
}
this.activator = function() {
interval = setInterval(PopulateData, 1000); // run every second
};
}
var example_obj = new DataFeed();
example_obj.activator();