I want to run delay function as part of my underscore chain.
It seems like delay function is only able to work with explicit argument passed - not the wrapper object.
This code does not work (undefined is not a function exception):
var message = function (text) {
var txt = text;
var show = function () { alert(txt); };
return {
Text: txt,
Show: show
};
};
_.chain(new message("hello")).delay(function(m) { m.Show(); }, 1000);
This code works:
var x = _.chain(new message("hello")).value();
_.delay(function (m) { m.Show(); }, 1000, x);
Is there a way to make delay work inside of a longer functional expression?
E.g. I want to defer viewmodel instance creation and then delay binding to UI by X ms.
What chain() does in underscore is just pipe its argument through all the following functions, passing it as first argument to those functions.
Since first argument to delay() should be a function then to achieve functionality you desire you'd have to do something like this:
_.chain(function(m) {
m.Show();
}).delay(1000, new message("hello"));
but I guess it doesn't have the structure you desire.
So you can't use delay() directly, but you can use it via tap():
_.chain(new message("hello"))
.tap(function(m) {
_.delay(function() {
m.Show();
}, 1000);
})
or even more concisely with use of tap() and bind():
_.chain(new message("hello"))
.tap(_.delay.bind(null, function(m) {
m.Show();
}, 1000))
If you wan't to pass in collection to chain() and do a delay() for every element of the collection use each() instead of tap().
The following is not an answer as it uses rather github.com/kriskowal/q promises than underscore.js but that's what I think you are trying to do, namely push something through a pipeline of operations some of them async:
var message = function (text) {
var txt = text;
var show = function () { alert(txt); };
return {
Text: txt,
Show: show
};
};
function delay(time) {
return function(m) {
var next = Q.defer();
setTimeout(function() {
next.resolve(m);
}, 1000);
return next.promise;
}
}
Q.when(new message("hello"))
.then(delay(1000))
.then(function(m) {
m.Show();
});
The first argument of _.delay must be a function, but u pass a instance if message class (object).
f.e.
var foo = function(){
console.log('FOO');
}
_.chain(foo).delay(200);
And to use chain in your case is overhead. Try something like that:
var showMsg = function(){
var msg = new message("hello");
msg.Show();
};
_(showMsg).delay(200);
Related
Can anybody give me tutorial how this function is working i am not able to understand how this function is working. How this.go function actually working. Any Help would be appreciated. Thanks
var Middleware = function() {};
Middleware.prototype.use = function(fn) {
var self = this;
this.go = (function(stack) {
return function(next) {
stack.call(self, function() {
fn.call(self, next.bind(self));
});
}.bind(this);
})(this.go);
};
Middleware.prototype.go = function(next) {
next();
};
USAGE
var middleware = new Middleware();
middleware.use(function(next) {
var self = this;
setTimeout(function() {
self.hook1 = true;
console.log('a')
next();
}, 10);
});
middleware.use(function(next) {
var self = this;
setTimeout(function() {
self.hook2 = true;
console.log('b')
next();
}, 10);
});
var start = new Date();
middleware.go(function() {
console.log(this.hook1); // true
console.log(this.hook2); // true
console.log(new Date() - start); // around 20
});
The purpose of this code seems to be to build up a sequence of functions, which will then be run one after the other.
The go method's job is to run some code. If you've never called use, then go will run the specified code immediately, with no complications.
The use method lets you insert additional steps to be run. When you call use, the original go method is replaced with a new method. That new method will call the old go method, followed by your custom method. If use is called multiple times, this builds up a sequence of functions. The functions will be called in the order they were passed in to use. The next function starts running when the previous function calls next().
A lot of the complication of the code comes from making sure that the value of this stays what it's expected to be. If that wasn't a requirement, then use could be rewritten like this:
Middleware.prototype.use = function(fn) {
const oldGo = this.go;
this.go = next => oldGo(() => fn(next))
}
So i'm using angularJS and$q service. But for simplicity i'm using $timeout since it creates a promise.
Question:
Is it possible to only return a promise when a conditional has been satisfied? For this example, I want to wait for carousel.params.caruselReady to return true before I move to next .then.
$timeout(function(){
if(Carousel.params.ready()){
return ready;
}
},0).then(function(ready){
//...do stuff..//
}
Carousel.params.ready is coming from Carousel.js a factory:
//this function gets called everytime a image has been loaded. when all images are rendered than carousel is ready
carouselElLoaded: function (result) {
var count = 1;
Carousel.params.pageRenderedLength += count;
if (Carousel.params.pageRenderedLength >= Carousel.params.pageLength) {
Carousel.params.carouselReady = true;
}
},
Lastly, carouselElLoad is being called from wa.pages.js (a directive)
$img.onload = function (e) {
var self = this;
$timeout(function () {
return self;
}, 0).then(function () {
Carousel.set.carouselElLoaded(e);
});
};
Currently, I'm using a $watch to achieve this but I was wondering if I could accomplish the same w/o a watcher.
You can use a promise instead of a boolean flag and it will do exactly what you want.
In Carousel.js define a promise names isCarouselReady and resolve it once the carousel is ready, your code should like something like this:
// During the initialisation of your factory
var carouselDeferred = $q.defer()
Carousel.params.isCarouselReady = carouselDeferred.promise;
//this function gets called everytime a image has been loaded. when all images are rendered than carousel is ready
carouselElLoaded: function (result) {
var count = 1;
Carousel.params.pageRenderedLength += count;
if (Carousel.params.pageRenderedLength >= Carousel.params.pageLength) {
carouselDeferred.resolve(/* What ever you'd like here */);
}
},
Now you all you have to do in order to use it is:
Carousel.params.isCarouselReady.then(function() {
// Your logic
});
Your last part would be nicer if it would look something like this:
$img.onload = function (e) {
$scope.$apply(function(){
Carousel.set.carouselElLoaded(e);
});
};
I have some code like:
var bar = foo().then(function success(value) {
// compute something from a value...
}, function failure(reason) {
// handle an error...
});
How do I bind the failure function to the this object in the context of bar. I know I will have to use myFunc.bind(this) but what do I substitute in place of myFunc?
You can use bind like this:
var bar = foo().then(function success(value) {
// compute something from a value...
}, function failure(reason) {
// handle an error...
}.bind(this));
You currently have an anonymous (although labelled) function for your failure callback:
function failure(reason) {
// handle an error...
}
As robertklep says, you can immediately call .bind on that anonymous function. However, it might be more readable to use a named function instead, and pass it into .then() as a variable:
function success(value) {
// compute something from a value...
}
function failure(reason) {
// handle an error...
}
var bar = foo().then(success, failure.bind(this));
If you are only interested in the object this of the enclosing scope, and you are using ECMA6 or later, you could use arrow functions. It would look like:
var that = this;
var bar = foo().then(value => {
// compute something from a value...
console.log(this === that); // true
this.propA = value.propA
});
You could find more examples in MSD Using promises
What I found very useful is to bind each then()'s [function] handler to the one empty object, so each function could have the access to it. Then the user can set and get the properties in each Promise by this keyword. The unit test frameworks works similarly.
chainPromiseList([getName,getAge],finalDone,rejectHandle);
function chainPromiseList(promiseList,finalDone,errHandle){
var userContext = new UserContext();
if(typeof finalDone==='function') promiseList.push(finalDone);
if(typeof errHandle==='function') promiseList.push(errHandle);
return promiseList.reduce((total,curVal,curInd,arr)=>{
var last = curInd+1===arr.length;
var method = last&&typeof errHandle==='function' ? 'catch':'then';
var concatenated = total[method](curVal.bind(userContext));
return concatenated;
},Promise.resolve());
function UserContext(){};
}
function getName(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('got name!');
this.name = 'Paul';
resolve();
},500);
});
}
function getAge(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('got age!');
this.age = 26;
resolve();
},500);
});
}
function finalDone(){
console.log(`Hello, I'm ${this.name} and I'm ${this.age}yo.`);
}
function rejectHandle(msg){
console.log('Error: ',msg);
}
i have this example:
var myApp = (function() {
var inputClick = function() {
console.log('inputClick');
};
var loadRecentTimeout = function()
{
window.setTimeout("inputClick()",3000);
};
return {
loadRecentTimeout:loadRecentTimeout,
inputClick:inputClick
};
})();
myApp.loadRecentTimeout(); // this returns inputClick() undefined
window.setTimeout("myApp.inputClick();",3000); // this one seems to work , but it calls that method only one time and not every 3 seconds
can anyone explain how can i make this code call the inputClick() method every 3 seconds?
thanks
You want to call setInterval instead of setTimeout
var eventInterval = window.setInterval(function () {
myApp.inputClick();
},3000);
You also should pass your function as a function instead of a string.
If you need to cancel your repeating event you can call clearInterval
clearInterval(eventInterval)
When you use a string "functionName()" it evals it in window scope. Instead, assign a reference to the function with just using the name. setTimeout only fires once, you want to use a setInterval.
var myApp = (function() {
var inputClick = function() {
console.log('inputClick');
};
var loadRecentTimeout = function()
{
window.setInterval(inputClick,3000);
};
return {
loadRecentTimeout:loadRecentTimeout,
inputClick:inputClick
};
})();
I found a bug, and tracked it down.
You can see a simplified example of my code here.
As it turns out, I need to debounce my if() statement rather than debouncing the function itself.
I'd like to keep the debounce as a standalone function, but I'm not sure then how to pass the conditional in.
Any pointers?
Here's the code:
var foo = function(xyz) {
alert(xyz);
};
function setter(func, arg1, arg2) {
return {
fn: func,
arg1: arg1,
arg2: arg2
};
}
function debounce(someObject) {
var duration = someObject.arg2 || 100;
var timer;
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(function() {
someObject.fn(someObject.arg1);
timer = 0;
}, duration);
}
var toggle = true;
if (toggle) {
debounce(setter(foo, 'The best things in life are worth waiting for.', 1250));
} else {
foo('Instant gratification is sweet!!');
}
Using your example, why not pass toggle in as arg 1... something like:
var toggle = true;
var debouncedFunk = function(toggle) {
if (toggle)
// the function call
else
// something else
};
debounce(debouncedFunk, toggle, 1250);
You should also look into using the Function objects .call and .apply methods. They are for calling the function and passing in arguments. Taking the example function:
var example = function(one, two) {
// Logic here
};
You can call it in three ways:
// First
example(1, 2);
// Second
example.call({}, 1, 2);
// Third
example.apply({}, [ 1, 2 ]);
The first is the standard way to call a function. The difference between the first and the .call is that the first parameter to .call is the context object of the function (what this will point to inside the function), the other parameters are passed after that (and a known list is required for .call. The benefit of .apply is that you can pass an array to the function of arguments and they will be assigned to the parameter list appropriately, the first parameter is still the context object.
It would simplify your debounce function, instead of having to deal with a structured object as you currently do.
A suggestion for your debounce:
var debounce = function(funk, delay) {
var args = [];
if (arguments.length > 2)
args = [].slice.call(arguments, 2);
setTimeout(function() { funk.apply({}, args); }, delay);
};
Changing your current if to:
var toggle = true;
var debouncedFunk = function(toggle) {
if (toggle)
// Do if true
else
// DO if false
};
debounce(debouncedFunk, 1000, toggle);
Maybe too much information (sorry)?
As a last note, I'd recommend using a framework (if possible) where these functions have been implemented already (and many other useful functions) such as Underscore. Using Underscore your example would look like:
// Define debouncedFunk and toggle
debouncedFunk = _.bind(debouncedFunk, {}, toggle);
debouncedFunk = _.debounce(debouncedFunk, 1000);
debouncedFunk();
EDIT
Fixed the underscore example, _.debounce returns a function that will execute only after the delay but it still needs to be called.