Just a word of caution in general remember there's always more to this stuff than meets the eye.
People will try to simplify it for you and in the process they leave important stuff out.
This turns into a meme that people will just keep repeating to each other mindlessly, one of them is "oh promises haha it's nothing just a placeholder for a future value".
That's like saying "haha look at this car ... it's just a moving metal box". It's not false, but it also doesn't do it justice.
So after you hear these oversimplified descriptions don't be fooled into thinking that was it! and you have now learned all that there is to know about promises, or whatever.
Just to give you a taste of what I'm talking about, go read this article which does a good job of highlighting the little details that no one talks about:
http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html
Author of the article here. This is the correct answer. :)
Jake Archibald also goes into some detail in this post. The Q library offers exactly such a spawn()
helper method, which you can use if you're on ES6 and can't use ES7.
What I like I about ES7 async functions, though, is that they are more widely applicable to promise-returning libraries like PouchDB. Imagine how much simpler our API examples could be if we could just tell people to use await
, instead of going into a lengthy discussion of promises!
The author, to me, seems to have some vendetta with the current state of JavaScript and instead of weighing the pros/cons of a different approach to a non-concurrent, async language, it just seemed like a lot of bashing. Comparing it with a library in Python is like Apples and Oranges.
Promises are much cleaner than callbacks, because they provide similarity in control flow between synchronous & asynchronous calls. A synchronous function is either:
With async functions, a return value just may not be available, or an exception may have not been thrown yet. Callback hell is awful, we all know this, but it's a way to handle the exceptions or values that may be returned later. The point of promises, is to give us back functional composition and error bubbling. Promise functions are not callbacks, they are transformations.
Also to mention, some of the features around handling multiple promises and the ability to disband a promise.
Either way, if you don't like Promises, there's always the newer ES7 <strong>async-await</strong> functionality as an alternative, already supported by babel.
For me, callbacks have two advantages as a main mechanism over promises:
- Even if promises are powerful, callbacks are easier to understand for any javascript developer. You can e.g. have a look at this article: http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html to see how you can easily shoot yourself in the foot with promises if you don't completely grasp what they do.
- It's easier to build abstractions from lower-level concepts than to go the other way around. Having functions and a defined interface using them for every async call allows client code to decide which abstraction it wants to rely on. If you prefer promises for your flow, then you can turn any function using the callbak pattern to a promise (most promise libraries give you a 'promisify' or 'denodeify' function to do it), and if you prefer something else, you can build it.
I'd admit that I prefer promises for my control flow, but I think that having callbacks as base mechanism empowers the community by letting anyone build what ever she wants on top of it.
I have to disagree with notion that there's something inherently wrong with nesting callbacks. Yes, it's wrong in the node.js world because callbacks managing callbacks become impossible to manage very quickly. But in Ruby world, 3 nested callbacks are mostly likely just 3 lines of synchronous code. It's neat, manageable, debuggable etc. That's what I miss about synchronous programming.
I've been using promises which lets me do
asyncFunction1() .then(function(result) { return asyncFunction2(); }, function(err) { // do something about err }) .then(function(result) { // do more... }, function(err) { // do something about err });
Which looks way better than nested callbacks.
And in ES7 , it's looking even more promising. It looks almost like synchronous code.
> 3 drinks sounds like an INTJ level of planning out the night :P
It's kind of a Si ritual haha. I have no social plans tonight so I'll have dinner with three beers while I play around with this shit: http://pouchdb.com/
Also your body doesn't tell you when you're developing all sorts of long term problems. Science is pretty decent at it most of the time though. Your body evolved to get you through having babies and likely living long enough that they're self sufficient. Everything else is just cruft. A 35 year old with achy joints will likely have fewer kids. A 55 year old with achy joints is likely already dead anyways but if not meh, evolution doesn't give a shit.
That looks perfect to me; nicely done! The next step, of course, would be to make sure you understand why it works. If you have time, I would take a look at how promises work. They can be a bit complicated, and there's a lot of ways to get it wrong, but understanding them will make your angular code (and your javascript in general) a lot more flexible. In fact, before I understood promises, I wrote a rather large web application following the same pattern you were using (having your $http calls right in your controller so I didn't have to worry about promises). I can safely say that pattern does not scale well.
Here are a couple of resources I'd recommend, though I don't know how well you know promises already so I apologize if these aren't helpful:
I haven't used it in JavaScript, but given that the syntax is the same as C#, you're probably looking at something like this:
async myFuncAsync() { var a = db.get(...); var b = db.get(...); var c = db.get(...);
await a; await b; await c; }
In C# you'd use Task.WhenAll()
rather than consecutive awaits like that. It looks like JavaScript supports something similar:
async myFuncAsync() { var promises = [ db.get(...), db.get(...), db.get(...) ];
await* promises; }
Look under concurrent loops.
This isn't really eli5, but I think it does a good job of explaining the ways promises can be used and how they behave in different situations. Its good if you have a basic understanding of promises already (which I'm assuming you do with the previous links?).
http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html
The difference is that when something is asynchronous, the API method doesn't return
anything immediately useful to you. A good example is this PouchDB API doc. Notice how in the second example, we need the result of get()
before we can put it into put()
.
This will end up looking more like your code snippet, though, when we get to ES7 and async/await.
I recommend taking a look at KnockoutJS. It is not as full featured as other frameworks, but it sounds like your main need is data-binding. KnockoutJS is great for that and very easy to get started with.
It officially supports IE6+.
> one of my loftier goals is to have things work offline and resync with the server once connectivity is restored
I would also like to do this for one of my hobby projects. I've done a lot of reading about how to accomplish this, but made no steps to pursue it.
One of the solutions I'm considering is PouchDB.
>Today you can write an app that: > > - Syncs from CouchDB to an in-memory PouchDB Server, > - Then syncs to LocalStorage on IE 8, - Then syncs to Cloudant, - Then syncs to a PhoneGap app using the SQLite Plugin, - Then syncs to any one of Redis, Riak, SQLite, LevelDB, MySQL, PostgreSQL, and potentially many more. > Or whatever other crazy combination you can cook up!
Have you looked at pouchdb http://pouchdb.com
It's like couchdb. It's nice. Focused on being browser based but works well on the server side too.
--
PouchDB is an open-source JavaScript database inspired by Apache CouchDB that is designed to run well within the browser.
PouchDB was created to help web developers build applications that work as well offline as they do online. It enables applications to store data locally while offline, then synchronize it with CouchDB and compatible servers when the application is back online, keeping the user's data in sync no matter where they next login.
If you like error handling with Promises compared to error handling with async/await, then that's like preferring a tooth pick for buttering your toast instead of using an actual butter knife. Code is much easier to read with the async/await syntax (in my humble opinion). Here's a few articles that might show the benefit of async/await (although one is using generators, but the same concept can be applied using async/await):
http://pouchdb.com/2015/03/05/taming-the-async-beast-with-es7.html
http://jlongster.com/Taming-the-Asynchronous-Beast-with-CSP-in-JavaScript
Have a look at PouchDB, it'll help you store structured data client-side.
Also realize that:
> best score will be picked for prizes
combined with
> can work offline
means it's possible for people to cheat with a little Javascript or developer tools hackery.
You could use something like PouchDB to store data directly in the browser with JavaScript, no native plugin required. It abstracts WebSQL/IndexedDB for you so you should only need to write your data access once.
Well depends what are you running on your client side?
I will assume html/js. Then I will recommend pouchdb
save your client data to a local pouchdb instance, replicate it to couchdb, if you are willing to play with a blade you can try websockets
https://github.com/nolanlawson/socket-pouch
So for example to set information you will do a db = pouchdb("awesomeGame")
.
Then post simple json to your db
var player = { "_id: "playerXYZ", "health": "100", "weapons": [ "RPG", "Grenades", "pistol" ] "location": { "x": 428, "y": 271 }, }
db.post(player)
you can also get it `db.get("playerXYZ") anywhere you want it.
Yeah, the idea is to push cross-cutting concerns somewhere else. You could for instance take that persist decorator and apply it to some other components in a more complex application (avoids duplication). You can also apply it to other projects easily.
On more general level the benefit of having localStorage persistency here is that it allows our application to work after refresh. Of course if there was a real backend this would be in vain but in this case we don't happen to have one so we needed to do something else. These approaches can be combined. You'll get some bonus problems (syncing offline data) to deal with. There are libraries such as PouchDB that solve it, though.
I will add a note about this to the book so it's clearer. Thanks!
loadPage(url) .then(parseRows) .then(connectDb, handleError) .then(setDb) .then(findStock) .then(filterStock) .then(tweetStock) .then(saveStock, handleError) .then(disconnectDb)
No error handling? See #3.
Also - ugh - really? Are developers chaining that many calls together?
There's some issues with the code, especially the assumed synchronous part at the end. The io from the function call will cause Existing to print before the io is complete.
Here's an article that might help.
http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html