Is there a best-practice solution to be able to use within in promise this? In jQuery i can bind my object to use it in my promise/callback - but in angularJS? Are there best-practice solutions? The way "var service = this;" i don't prefer ...
app.service('exampleService', ['Restangular', function(Restangular) {
this._myVariable = null;
this.myFunction = function() {
Restangular.one('me').get().then(function(response) {
this._myVariable = true; // undefined
});
}
}];
Are there solutions for this issue? How i can gain access to members or methods from my service within the promise?
Thank you in advance.
The generic issue of dynamic this in a callback is explained in this answer which is very good - I'm not going to repeat what Felix said. I'm going to discuss promise specific solutions instead:
Promises are specified under the Promises/A+ specification which allows promise libraries to consume eachother's promises seamlessly. Angular $q promises honor that specification and therefor and Angular promise must by definition execute the .then callbacks as functions - that is without setting this. In strict mode doing promise.then(fn) will always evaluate this to undefined inside fn (and to window in non-strict mode).
The reasoning is that ES6 is across the corner and solves these problems more elegantly.
So, what are your options?
Some promise libraries provide a .bind method (Bluebird for example), you can use these promises inside Angular and swap out $q.
ES6, CoffeeScript, TypeScript and AtScript all include a => operator which binds this.
You can use the ES5 solution using .bind
You can use one of the hacks in the aforementioned answer by Felix.
Here are these examples:
Adding bind - aka Promise#bind
Assuming you've followed the above question and answer you should be able to do:
Restangular.one('me').get().bind(this).then(function(response) {
this._myVariable = true; // this is correct
});
Using an arrow function
Restangular.one('me').get().then(response => {
this._myVariable = true; // this is correct
});
Using .bind
Restangular.one('me').get().then(function(response) {
this._myVariable = true; // this is correct
}.bind(this));
Using a pre ES5 'hack'
var that = this;
Restangular.one('me').get().then(function(response) {
that._myVariable = true; // this is correct
});
Of course, there is a bigger issue
Your current design does not contain any way to _know when _myVariable is available. You'd have to poll it or rely on internal state ordering. I believe you can do better and have a design where you always execute code when the variable is available:
app.service('exampleService', ['Restangular', function(Restangular) {
this._myVariable =Restangular.one('me');
}];
Then you can use _myVariable via this._myVariable.then(function(value){. This might seem tedious but if you use $q.all you can easily do this with several values and this is completely safe in terms of synchronization of state.
If you want to lazy load it and not call it the first time (that is, only when myFunction is called) - I totally get that. You can use a getter and do:
app.service('exampleService', ['Restangular', function(Restangular) {
this.__hidden = null;
Object.defineProperty(this,"_myVariable", {
get: function(){
return this.__hidden || (this.__hidden = Restangular.one('me'));
}
});
}];
Now, it will be lazy loaded only when you access it for the first time.
Related
Is it possible to use await inside a normal function?
For Example:
function myFunction(v1, v2) {
let v3 = await some db operation; returns a array
console.log(v3);
//do something
};
Yes, all async code is called from a normal function somewhere, but no you can't use the await keyword in a non-async function.
Async functions look like promises when inside non-async functions.
function myOuterFunction(v1, v2) {
myFunction(v1, v2)
.then(console.log)
.catch(console.error);
}
async function myFunction(v1, v2) {
let v3 = await some db operation; returns an array
console.log(v3);
//do something
};
(This example uses the functions console.log and console.error to handle returned values and exceptions.)
No, and for a good reason.
Before async functions were introduced: the following was entirely possible:
function foo() {
var await = 42;
var result = await + 42;
}
If they had made it so await was available in normal functions, that code would have been retroactively broken, causing what's called a backwards compatibility break.
This is also why yield is only available within function*.
No. The "magic" of asynchronous programming – that, in JavaScript, includes the usage of await – is that it doesn't block the execution of other code. If you want to use it, you have to adapt your codebase to use async functions where it makes sense.
If you really need to wait for asynchronous actions to complete inside normal synchronous functions, you could check whether the library you're using also offers sync functions (fs-extra for example does). But please, unless there's a really good reason not to, make your code asynchronous.
I'm trying to get my head around callbacks in Node.JS and it's pretty foreign compared to what I'm used to.
I have the following example from another post on here:
var someOutput;
var myCallback = function(data) {
console.log('got data: '+data);
someOutput = data;
};
var usingItNow = function(callback) {
callback('get it?');
};
//now do something with someOutput outside of the functions
I have added the someOutput variable - I want to get the text 'get it?' (obviously I don't) into there so that I can concatenate it on to a string, but it's not working in any combination I've tried.
I must be missing something fundamental here!
Thank you for the help.
You should call the function:
usingItNow(myCallback);
But anyway it is not a good practice to use callback to set variable and consume later. It will work for you now, but later if callback will be async, it will fail.
Consider using Promise and use someOutput in the then function.
A good Promise package is Bluebird
If you want to do it like a pro, consider using Promise.coroutine
http://bluebirdjs.com/docs/api/promise.coroutine.html
Or async + await if you are using an updated version of Node.js
Look on http://node.green/#ES2017-features-async-functions to check what avilable on your node version
As commented by emil:
"call usingItNow(myCallback);"
doh!
A methodological question:
I'm implementing an API interface to some services, using node.js, mongodb and express.js.
On many (almost all) sites I see code like this:
method(function(err, data) {
assert.equal(null, err);
});
The question is: should I keep assert statements in my code at production time (at least for 'low significance' errors)? Or, are these just for testing code, and I should better handle all errors each time?
You definitively should not keep them in the production environment.
If you google a bit, there are a plethora of alternative approaches to strip out them.
Personally, I'd use the null object pattern by implementing two wrappers in a separate file: the former maps its method directly to the one exported by the module assert, the latter offers empty functions and nothing more.
Thus, at runtime, you can plug in the right one by relying on some global variable previously correctly set, like process.env.mode. Within your files, you'll have only to import the above mentioned module and use it instead of using directly assert.
This way, all around your code you'll never see error-prone stuff like myAssert && myAssert(cond), instead you'll have ever a cleaner and safer myAssert(cond) statement.
It follows a brief example:
// myassert.js
var assert = require('assert');
if('production' === process.env.mode) {
var nil = function() { };
module.exports = {
equal = nil;
notEqual = nil;
// all the other functions
};
} else {
// a wrapper like that one helps in not polluting the exported object
module.exports = {
equal = function(actual, expected, message) {
assert.equal(actual, expected, message);
},
notEqual = function(actual, expected, message) {
assert.notEqual(actual, expected, message);
},
// all the other functions
}
}
// another_file.js
var assert = require('path_to_myassert/myassert');
// ... your code
assert(true, false);
// ... go on
Yes! asserts are good in production code.
Asserts allow a developer to document assumptions that the code makes, making code easier to read and maintain.
It is better for an assert to fail in production than allow the undefined behaviour that the assert was protecting. When an assert fails you can more easily see the problem and fix it.
Knowing your code is working within assumptions is far more valuable than a small performance gain.
I know opinions differ here. I have offered a 'Yes' answer because I am interested to see how people vote.
probably no
ref: When should assertions stay in production code?
Mostly in my code i put error handling function in a separate file , and use same error method everywhere, it mostly depends on logic anyways
like ppl generally forget this
process.on('uncaughtException', function (err) {
console.log(err);
})
and err==null doesn't hurts , it checks both null and undefined
This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Waiting for async call
(1 answer)
Closed 8 years ago.
I have a User model function all that returns all users in an array.
User = {
all: function() {
var users = [];
globalLibrary.db.collection('users').find({}).toArray(function(err, items) {
test.equal(null, err);
users = items;
});
return users;
}
}
I want to ensure that the function doesn't finish or return before the mongodb query is complete.
Currently, this function is just returning [], and querying mongodb asynchronously. I want the function to wait until the function finish query is complete and it returns and array filled with users.
Note:
globalLibrary.db is just a cached mongodb connection.
My solution using promises
Since some people closed the question as a duplicate, I'll write my answer here within the question. Hopefully someone else who is not familiar with asynchronous programming find this useful.
Problem
The point is that you need to use a callback - there's no way to block
on something asynchronous. (...) – Aaron Dufour
The function User.all() I wrote above will return empty array because nothing is stopping the process while the mongodb query is happening. There are some primitive ways to stop the process.
You can crank up some hacky stuff using setTimeout(). This way sucks though because you have to use some arbitrary time that might be higher than the actual time you need to query the mongodb. Simply put, it's slower.
You can also use some event based stuff that #AaronDufour linked in the comment (now deleted). So you can have something a pair of event emitter and a listener to replace setTimeout() way. #Someone points out though that you shouldn't use this in node.js for blocking function.
Now finally, the conventional way of dealing with this problem is using callbacks as pointed out by the answer below. This is fine, but callbacks can quickly get out of control once you start having multiple callbacks stacked inside one another.
I am using https://github.com/kriskowal/q for promises. While using promises doesn't solve all the woes of callbacks, but it looks most like simple synchronous programming style which I think is a huge plus.
First do npm install --save q to start using Q package.
Here's my new User.all() function.
var Q = require('q')
var Users = {
all: function() {
var deferred = Q.defer();
globalLibrary.db.collection('users').find({}).toArray(function(err, items) {
if (err) {
deferred.reject(new Error(err));
} else {
deferred.resolve(items);
}
});
return deferred.promise;
}
}
Now if you want to use User.all().
User.all()
.then(function (docs) {
// docs is the array of returned users from mongodb query.
console.log(docs);
}, function(error) {
// do something if there's an error.
}, function(progress) {
// do something while the query is running.
});
The preferred way of doing this in node.js is to embrace the async nature of it and pass in a callback to the function. A few decent tutorials (last one including mongodb examples):
http://justinklemm.com/node-js-async-tutorial/
http://msdn.microsoft.com/en-us/magazine/dn754378.aspx
If you feel you must go against the grain and go synchronous, I'd take a look at this sync library for node.js and mongodb:
https://www.npmjs.com/package/mongo-sync
I know out of the box Q won't support this, but I'm wondering if it is theoretically possible to do something like this:
var user = Q.spawn(function* () {
var createdUser = yield createUser();
return user;
});
console.log(user); // user is available here
I may be wrong, but I would say yes, it is possible theoretically, it's just not intended to work like that. That's why Q doesn't support it.
I'm not sure why Q.done doesn't invalidate the promise chain altogether, preventing further calls to p.then to succeed (maybe it's impossible), but right now (Q is at version 1.2.0 at the time of this writing) it doesn't:
var p = Q("Test");
p.done();
p.then(function(message) {
console.log(message); // "Test" is logged here just fine.
});
// No runtime errors.
So Q.spawn needed only return the result of Q.async(generator)() after calling Q.done on it to support that, like this:
Q.spawn = spawn;
function spawn(makeGenerator) {
var p = Q.async(makeGenerator)();
Q.done(p);
return p;
}
That said, it seems clear to me that the API doesn't want to encourage using a done promise chain: Contrary to Q.then and Q.catch, for example, neither Q.done nor Q.spawn return any promise for chaining.
The library authors were either not sure if this was a good idea (and so didn't want to encourage it, but didn't also implement something that prohibits done promises from being used) or were outright convinced it's not.