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);
}
Related
I have this function:
waitForFreeAccnt.prototype.isMemberFree = function () {
var self = this;
self.api.getMemberInfo(function () {
var accType = self.api.connect.accountType;
console.log(accType);
if (accType === 'FREE') {
console.log('it is free');
return true;
} else {
console.log('it is not free');
return false;
}
});
};
I would like to wait till the account is free for up to 10 seconds with something like that:
var test = function () {
for (var start = 1; start < 10; start++) {
var result = self.isMemberFree();
console.log(result);
if (result) {
break;
} else {
self.api.pause(1000);
console.log('waiting');
}
}
};
But it doesn't work because self.api.getMemberInfo is asynch call. This is super frustrating with Javascript. Any other language it would be so simple to do. How do I force the for loop to wait for self.isMemberFree() to finish executing before proceeding with the loop?
Also to note, this is not in browser execution so I don't care about anything hanging.
When dealing with asynchronous code, you need to make use of callbacks. That is, if you want to do a() and b() in order but a() does something asynchronously, then you need to call b() from within a() once a() has a result. So not:
a(); // does something asynchronously
b(); // tries to use a()'s result but it isn't available yet
... but rather
a(b); // pass b to a() and a() will call it when ready
function a(callback) {
triggerAsyncFunction(function(result) {
if (result === something)
callback("a just finished");
});
}
Note that a() doesn't refer to b() by name, it just calls whatever function is passed in as an argument.
So applying that to your code, maybe something like this:
waitForFreeAccnt.prototype.isMemberFree = function (cbf) {
var self = this;
self.api.getMemberInfo(function () {
cbf(self.api.connect.accountType === 'FREE');
});
};
waitForFreeAccnt.prototype.testMemberXTimes = function(maxAttempts, callback) {
var attempts = 0;
var self = this;
(function attempt() {
self.isMemberFree(function(free) {
if (free)
callback(true);
else if (++attempts < maxAttempts)
setTimeout(attempt, 1000);
else
callback(false);
});
)();
};
this.testMemberXTimes(10, function(isFree) {
// the next part of your code here, or called from here
// because at this point we know we've tested up to
// ten times and isFree tells us the result
});
Note that the way I coded getMemberInfo() it is basically doing the same thing yours was, but instead of returning a boolean it is calling the callback function and passing the same boolean value that you were returning. (I've removed the console.log()s to make the code shorter.)
Note also that you could structure the above to use promises, but the end result will be the same.
You could return a Promise
waitForFreeAccnt.prototype.isMemberFree = function () {
return new Promise((reject, resolve)=>
// set a timeout if api call takes too long
var timeout = setTimeout(()=> reject(Error('API timeout')), 10000);
// make api call
this.api.getMemberInfo(()=> {
clearTimeout(timeout);
resolve(this.api.connect.accountType === 'FREE');
});
);
};
Then use it like this
whatever.isMemberFree().then(isFree=> {
if (isFree)
console.log('it is free');
else
console.log('it is not free');
})
// handle timeout or other errors
.catch(err=> {
console.log(err.message);
});
Building on naomik's answer, if you do it that way you can pretty easily use a for loop with it, using the (most likely) upcoming async/await feature - though it's not part of ES2015.
// Note "async" here! That will make "await" work. It makes the function
// return a promise, which you'll be able to either "await" or
// "test().then" later.
var test = async function () {
for (var start = 1; start < 10; start++) {
// Right here we're using "await" - it makes JavaScript *wait* for
// the promise that comes from self.isMemberFree() to be finished.
// It's really handy because you can use it in loops like "for" and
// "while" without changing the flow of your program!
var result = await self.isMemberFree();
console.log(result);
if (result) {
break;
} else {
self.api.pause(1000);
console.log('waiting');
}
}
};
For now you'll need to use a transpiler like Babel or Traceur before you can really use async/await, though. It's only supported in Microsoft Edge 14 right now.
And a big emphasis that what is returned from test() isn't whatever you directly return from inside it. If I do this:
var test = async function() { return 15; };
var result = test();
I'm not going to get 15 - I'll get a promise that will resolve as 15:
result.then(function(res) {
console.log(res); // 15
});
// or, use an async function again:
var main = async function() {
console.log(await res); // 15
};
main();
I don't have my work laptop today because it is Sunday, I'm coding this on sublime. Apologise if the syntax is a bit off.
To solve your problem I would recommend changing isMemberFree() to take in a callback function. This is because isMemberFree is async, and you will need a way to report the result after it has done the work.
Then change test function to use setTimeout API to wait a second.
Wrap the function call for isMemberFree() to be in a nested function and call it recursively, that way you'll have synchronize control over the async calls.
Look at the coding example:
waitForFreeAccnt.prototype.isMemberFree = function (done) {
var self = this;
self.api.getMemberInfo(function () {
var accType = self.api.connect.accountType;
console.log(accType);
if (accType === 'FREE') {
console.log('it is free');
return done(null, true);
} else {
console.log('it is not free');
return done(null, false);
}
});
};
var test = function () {
var testMembership = function(waitAttempt, isFree) {
if (isFree) {
return;
}
else if (waitAttempt > 10) {
// wait exceeded, do something.
return;
}
setTimeout(function() {
self.isMemberFree(function(err, isFree) {
testMembership(waitAttempt+=1, isFree);
});
}, /*total milliseconds in 1sec=*/1000);
}
testMembership(/*WaitAttempts=*/0, /*isFree=*/false);
};
What the above code does is that, presumably something has already been done to the member's account and now test function is called. So it waits for 1 second, then call isMemberFree function, this happens recursively until either isMemberFree() returns true OR the 10 seconds wait has been exceeded.
I have 3 functions in my javascript code. I want to call the 3rd function as soon as both function1 and function2 are over executing.
func_one();
func_two();
func_three(); // To be called as soon both of the above functions finish executing.
Note that they may take variable time since function 1 and 2 are for fetching geolocation and some ajax request respectively.
How about this?
func_one() {
// Do something
func_two();
}
func_two() {
// Do something
func_three();
}
func_three() {
// Do something
}
There are two ways to solve this problem.The first one is to create callback functions as parameters for your existing functions.
function one(param_1 .. param_n, callback) {
var response = ... // some logic
if (typeof callback === "function") {
callback(response);
}
}
The second way is to use Promises like:
var p1 = new Promise(
function(resolve, reject) {
var response = ... //some logic
resolve(response);
}
}
var p2 = new Promise( ... );
p1.then(function(response1) {
p2.then(function(response2) {
//do some logic
})
})
You can try like this
var oneFinish = false;
var twoFinish = false;
function one(){
//...
oneFinish = true; // this value may depends on some logic
}
function two(){
//...
twoFinish = true; // this value may depends on some logic
}
function three(){
setInterval(function(){
if(oneFinish && twoFinish){
//...
}
}, 3000);
}
Since your functions func_one and func_two are making service calls you can call the functions on after other at the success callback of the previous function. Like
func_one().success(function(){
func_two().success(function(){
func_three();
});
});
I presume it is possible to create a JavaScript function that disables it self after it is done running.
Is possible? How can this effect be achieved?
Wrap arbitrary runnable in following manner:
function once(subject) {
var first = true;
return function() {
if (first) {
first = false;
return subject();
} else {
return null;
}
};
}
var wrapper = once(function() {alert("No more!");});
wrapper(); // alerts
wrapper(); // noop
Runnable will only be executed on first invocation of wrapper.
You can convert a function of arbitrary arguments to an argumentless runnable.
If you want the functionality to be happen only once you can use the following function
function once(fn, context) {
var result;
return function() {
if(fn) {
result = fn.apply(context || this, arguments);
fn = null;
}
return result;
};
}
// Usage
var canOnlyFireOnce = once(function() {
console.log('Fired!');
});
canOnlyFireOnce(); // "Fired!"
canOnlyFireOnce(); // nada
Courtesy: https://davidwalsh.name/essential-javascript-functions
something like this?
function a(){ alert(1); a = null;}
invoke a() once, second time it will say
Uncaught TypeError: a is not a function
if the function is anonymous, then make it IIFE
(function(){ alert(1);})();
var _flag = true; // Have a flag variable.
function oneTimer(){
// Check flag is set to true or not
if(!_flag) return;
_flag = false;
// Your function definition here.
}
As commented, if you want to execute a function only once, you should try IIFE. These functions are invoked immediately and cannot be called afterwards.
Following is a sample code.
(function test() {
console.log("test");
(function innerFunc() {
console.log("Inner Function");
})();
try {
innerFunc();
} catch (ex) {
console.log(ex)
}
})();
try {
test();
} catch (ex) {
console.log(ex)
}
Pretty easy, just assign an empty function to the function:
function once() {
alert('once');
once = function () { };
}
once();
once();
Sorry i couldn't come up with a straight forward question/title, but here's the thing. I have the following construct:
var userProvider=function(login){
this.getUser=mongoose.find(login).exec();
}
userProvider.prototype.doStuffWithUserData=function(){
this.getUser.then(function(user){
...
});
}
userProvider.prototype.doOtherStuffWithUserData=function(){
this.getUser.then(function(user){
...
});
}
Is there a a nicer way, such that i don't need to call the promise in every prototype function, though the prototype functions being evaluated only until the data is there?
Is there a a nicer way, such that the prototype functions being evaluated only when the data is there?
I'd recommend not to execute the find sideeffect in the constructor and create the promise there, but get the result of the mongoose.find(login).exec() passed into the constructor, as laid out in Is it bad practice to have a constructor function return a Promise?
I'd go with the bad practice case
To avoid the repetition, you can create your prototype methods like this:
function userProviderMethod(n, m) {
UserProvider.prototype[n] = function() {
var args = Array.prototype.slice.call(arguments),
that = this;
return this.getUser.then(function(user) {
args.unshift(user);
return m.apply(that, args);
});
};
}
function UserProvider(login){
this.getUser = mongoose.find(login).exec();
}
userProviderMethod("doStuffWithUserData", function(user /*, … */) {
// …
});
userProviderMethod("doOtherStuffWithUserData", function(user) {
// …
});
Notice that none of these "methods" will actually ever get executed when .getUser did get rejected.
Here is how you can do it with decoration. This is tricky because the promise is not available when you create the function yet:
function whenReady(fnToRun){
return function runsWhenReady(){ // the decorated function
// keep track of arguments
var args = Array(arguments.length + 1); // inline slice is much faster
for(var i = 0; i < arguments[i]; i++) args[i+1] = arguments[i];
return this.getUser.then(function(user){
args[0] = user;
return fnToRun.call(this, args); // append user and call with args
}.bind(this)); // maintain context)
};
}
This would let you do:
userProvider.prototype.doStuffWithUserData = whenReady(function(user){
// user is available here
});
myUserProviderInstance.doStuffWithData(); // inside the call user is available
userProvider.prototype.otherStuff = whenReady(function(user, x){
// user is available here
});
myUserProvider.otherStuff(15); // x will be 15 and user will be available, promise returned
This approach can be generalized to a more general whenReady that takes a "waitFor" argument. It's also worth mentioning that if you use a library like Bluebird it already ships with bind and method which let you do this in a more easy way.
I want to define a read-only object property that asynchronously fetches a value and then returns it using the new EcmaScript 5 getters.
However, the property always returns undefined even though magicValue in the example code below is definitively never undefined. Also, when I just return 'xxx'; the printed value is still undefined. It only works when I return outside the callback function.
It seems like return is being executed immediately regardless of whether the callback of myAsyncFunction is called.
I am not sure whether this a bug in in V8 or if I am abusing JavaScript's getters.
Can I get this to work? I thought, since I can use getters and setters now, I will use getters/setters to read and write properties and regular functions to do certain tasks.
var User = function (id) {
this.id = id;
};
Object.defineProperty(User.prototype, 'magic', {
get : function () {
myAsyncFunction(function (magicValue) {
return magicValue;
});
}
});
var u = new User(5);
console.log(u.magic);
Prints undefined.
Asynchronous operations, these days, are typically handled with Promises. When you invoke your getter, it returns a promise, which you can attach a callback with using the 'then()' method.
Object.defineProperty(User.prototype, "magic", {
get: function() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(JSON.stringify({
magic: 'value'
}));
}, 1000);
});
}
});
Here is a working example:
https://jsfiddle.net/tw6gaudz/2/
Thanks #utkanos for your help.
JavaScript won't acynchronously return a getter function's value because getters are synchronous.
You could use a "setter":
var User = function (id) {
this.id = id;
};
Object.defineProperty(User.prototype, 'magic', {
set : function (value) {
setTimeout(value.bind(0, "hello"), 1000);
return true;
}
});
var a = new User(5);
a.magic = function(msg){
alert(msg);
};