First, a quick update
Also, I didn’t initially manage to get the
CompatComponent from Ember Glimmer Component working to start using glimmer components. Once again, this is no longer an issue either.
I’ve updated the original post to reflect this, but in case you’ve already read it this might be worth mentioning here.
On the other hand, there is currently a bug with the latest version of Ember CLI, so you might want to check this link if you have an issue running
ember serve in your own applications using Ember CLI canary too.
So far my focus has been on file layout and components but with this post I want to switch gears and build on this with some of the forthcoming features that focus more on performance and handling asynchrony.
I’m going to continue developing the same application but progressing with more real-world use cases to illustrate the new functionality.
Promises and the run loop AKA taming asynchronous code AKA async/await
Not only that, but Ember itself also has it’s own way of grouping together tasks to make things work more efficiently. This is called the run loop and although the Ember guides provide a very good explanation of the motivation and way to use it I can honestly say it is still one of the parts of Ember that I am least confident about.
Whilst I was learning Ember itself I remember having to also get to grips with understanding promises too. Whilst promises are separate from the framework itself as they’re an integral part of working with Ember the net effect was to increase the learning curve with several different new concepts at the same time.
async/await is a more naturally intuitive concept anything like that which can help onboard people to using Ember more easily is a good thing.
If you have used Ember for a while there is a high chance you have run your test suite and seen the dreaded
You have turned on testing mode, which disabled the run-loop's autorun. You will need to wrap any code with asynchronous side-effects in a run loop . The great news is those days may soon be over.
As explained by Edward Faulkner in his excellent answer to a question about promises and RSVP (which is well worth a read in full).
Now that we can leverage the native microtask queue, we can make autoruns as robust as explicit run loops. The question of when to start and end the loop goes away — the native microtask queue is just always present. It’s always safe to schedule more work onto it, and rely on a native-task-based flush that will take care of all the “after” work. So the plan is to remove the assertion and just embrace autoruns, because they become no longer a problem.
Now this sounded brilliant, but it also demanded an understanding why microtasks exist and why they are something that we can now leverage. Again, Edward Faulkner helped me understand.
Up until Ember 3.0 (February 14, 2018) we supported browsers that didn’t have reliable, correct microtask scheduling. So Ember has long had it’s own built-in implementation of this same pattern: the runloop. The runloop achieves the same thing you would with the native microtask queue: it groups together work that’s supposed to go together, and lets you schedule what should happen “after” all that work has finished.
Put simply—before browsers had a native way to package up bits of work into specific tasks there was still a need to do so, hence Ember’s run loop.
Due to this fact promises (and
async/await) have also needed to interoperate with the run loop—which is why RSVP is still preferred to native promise support and
async/await has not really been adopted outside of writing tests.
This made sense to me—Ember innovated first so needed it’s own library but now that browsers have caught up it can migrate to the native versions, removing some of the now unnecessary prior complexity.
Unfortunately, I’ve had to regress to using callbacks many times because the Ember Run Loop breaks when testing code written with
async/await. He mentioned that this was something that needed to be fixed, and I would suggest it become a priority.
— A Road to Ember 4.0 by Andrew Callahan
There are a lot of places where you can already take advantage of them in Ember, particularly in our modern-style tests. But making them work everywhere is the same as making native Promises work everywhere, because they are just syntactic sugar for native promises. So everything above about Ember soon working with native promises also applies to
Now that all browsers support microtasks it’s just a matter of time before the run loop becomes something which the majority of Ember developers will no longer need to concern themselves with—it will just work.
But how long will this take?
In fact—good news! This issue has already been resolved and Ember is including a version of backburner that uses microtasks since
Knowing that microtasks (and therefore async/await and native promises) are now supported I thought a good place to try this out would be on a model hook.
As Ember ‘blocks’ a route’s template from displaying while waiting for the model’s promise to resolve it makes it a perfect place to load any data that is essential for the route’s content to display.
I began with the current conventional way of doing this—using a promise to delay the model return by two seconds.
This works as expected, but the same code can now be written without using promises or the run loop and by adopting the new
async/await syntax like this
Just as before, viewing this in the browser demonstrates that after a 2 second delay the tomster appears.
Personally, I find this style of code, which appears more like synchronous code, easier to rationalise in most instances.
Certainly promises still have their place and are an essential primitive to help manage asynchrony but, for me, there is something very appealing about being able to write asynchronous code in a way that feels much more like synchronous code.
It feels like another step change in making asynchronous code more comprehensible like the evolution from ‘callback hell’ to promises was.
In fact, anyone who has used Alex Matchneer’s Ember Concurrency library (and if you haven’t you should definitely check it out) might think it’s familiar.
async preceding the method name and
await to indicate some asynchronous code.
In terms of adopting
async/await my main remaining concern was whether or not testing would prove as successful as that seemed to be where in my experience most problems arose handling asynchrony were until now.
I think it’s fair to say that the testing story in Ember has become one of it’s real strengths.
Up until now I’ve avoided writing about tests in this experiment because, frankly, testing is now so good that it has already adopted into the mainstream many of these features — including the use of
So before cracking open the champagne on using this new coding style for application code I thought it would be the right moment to add a simple acceptance test which would test the new approach with an async model hook.
As mentioned earlier often the moment trouble rears it’s head using
async/await it’s during tests — as this issue for the model hook illustrates.
Running the test suite on the project showed that there was one failing component test—which was to be expected as the default blueprint test for the
tomster-logo component was no longer applicable.
Just in case you are unaware Ember comes pre-wired for testing and running the test suite is as simple as
EMBER_CLI_MODULE_UNIFICATION=true ember test --server
I decided that it made sense to update this test first to get it passing—and to see whether using the angle bracket syntax would cause any problems.
The next test, which was more relevant to this experiment, was to see if a test would still correctly display the route, using
async/await and a
setTimeout outside a run loop in the model.
For this it seemed most appropriate to use an acceptance test
EMBER_CLI_MODULE_UNIFICATION=true ember generate acceptance-test home
Then the test visits the application root and checks to see whether the correct text gets displayed.
Both tests passed with no problems.
Like so many of the forthcoming features in my first post this really does seem to ‘just work’ already now too.
My only slight disappointment was I was unable to get working the qunit-dom library, which seems like a nice way of cleaning up the code for assertions.
I’m still not sure why it didn’t work, as it looks like it is bundled by default in Ember CLI as of v3.2. It’s something I’m going to look into.
Honestly, I wasn’t too sure what to expect with this—it’s something which almost seems too good to be true. So far though, writing the tests seemed straightforward using these new features.
This is really going to be a great improvement and even just trying it out for this example makes me eager to start updating existing projects to this new syntax. I think lots of obscure bugs from promise chains will become much more obvious and fixable.
Removing jQuery AKA bye bye $, hello fetch
In a similar way that browsers have adopted better support for native promises and microtasks many of the reasons people reached for jQuery over the years have disappeared.
There is a great site You Might Not Need jQuery which attempts to show a non-jQuery equivalent for each potential use case you might have.
Many of these features, like
document.querySelectorAll() , which can replace the need to use
$() , have already been available in browsers since IE8.
Removing jQuery and other big, potentially optional dependencies from Ember is definitely something that should be carried on. Fewer dependencies equal possibly easier debugging.
— My Ember wishlist for 2018 by Dawid Pośliński
One big concern I’ve always had with dropping jQuery support though has not been so much my own application code but relates to AJAX requests.
Since the early days of Ember there have been different solutions to this like ic-ajax and ember-ajax but, as far as I know, they have all built off the underlying
jQuery.ajax() function. Ember Data itself, I understood, even uses it under the hood.
fetch came along which browsers began to adopt and things got even more confusing, especially with the announcement of Fastboot and with that the need of a dual approach for Ember apps—one for the browser, one for nodejs—became clear.
In fact, it proved to be information overload for me and so I decided to stick with the heard and to use
ember-data as I had always done and let the maintainers of those libraries guide my path.
I see this as another big advantage of using Ember where the community settles around a convention—I can focus on business needs and my own application code, knowing that very smart people are thinking about these hard problems and that sooner or later a good solution and semantic upgrade path will become apparent.
Despite the widespread support for
fetch, ember-ajax still relies on
jQuery.ajaxat its core and Pretender and ember-cli-mirage mock
XMLHttpRequest. I hope that these three libraries (and, through
AjaxServiceSupport, ember-data) will move to
— Ember 2018 Roadmap by James Rosen
But now that I’m using Ember CLI canary every time I run
ember serve I get a deprecation message about jQuery so it does make me wonder… maybe now it’s finally time to say goodbye to $ once and for all?
My experimental application doesn’t yet have any
AJAX requests or use Ember Data which doesn’t make it a good candidate for resolving any of the concerns I’ve just outlined.
On the other hand that means currently it should be straightforward to remove jQuery.
So my plan is to begin by removing jQuery and then use fetch instead of
jQuery.ajax() and once that’s working try to use Ember Data without jQuery too.
There’s an open pull request on getting Ember Data to use fetch, so it seems like eventually that will be the default approach anyway but it’s still in progress.
ember serve at the moment gives a deprecation message
DEPRECATION: You have disabled the `jquery-integration` optional feature. You now have to delete `@ember/jquery` from your package.json
So I followed the instructions and removed the dependency
yarn remove @ember/jquery
ember serve gives a different deprecation warning
DEPRECATION: Ember will stop including jQuery by default in an upcoming version. If you wish keep using jQuery in your application explicitly add `@ember/jquery` to your package.json
ember feature:disable jquery-integration
ember serve ran with no warnings—and without jQuery…
The library Ember Fetch is
Installing it is as simple as
ember install ember-fetch
To test it using as few external dependencies as possible I created by hand a JSON file for an endpoint in the
Incidentally, thanks to Edward Faulkner for using this technique in his Living Animation presentation which is where I discovered it.
If you are wondering what this format is, it’s called JSON:API which is a standardised spec for formatting JSON. It’s a convention Ember has adopted to make working with external data more consistent—but if your own service doesn’t conform to it then there are conventions for using any type of data.
Now, instead of pausing for 2 seconds, the routes uses
fetch to make an asynchronous request for the JSON data, formats it as JSON (another asynchronous method) and returns the correct data.
Using with Ember Data
It also includes the convention of an adapter—to quote the documentation
An Adapter determines how data is persisted to a backend data store. Things such as the backend host, URL format and headers used to talk to a REST API can all be configured in an adapter.
As mentioned previously, adapters currently do not use fetch.
In the meantime though there is an explanation of how to user
ember-fetch with Ember Data in the usage guide.
First, I checked to see if I could use the generate command to create the files in the right locations using the
In this case, it means a model file using the classes and the new decorators.
and an adapter file—to set the correct host and namespace but most importantly to include the mixin for
You can see that this file still extends the traditional
Ember.Object , rather than classes—and this is unfortunately still necessary.
Mixins are one part of the Ember object model that haven’t yet been adopted with classes and decorators. This is because it is still a bit contentious how best to approach it. For a better understanding why, here is an open PR on the ember-decorators repo, and an explanation why this is the case on the ES Classes RFC.
Finally, the route needs to be updated to use Ember Data’s store.
It turned out that both using
ember-fetch independently and using the
AdapterFetch Mixin in an adapter worked fine.
I noticed one deprecation warning for
deprecate-copy-copyable but as that deprecation isn’t yet even in the official guide I’m not too concerned.
Dropping jQuery was something that rather than being a major headache proved to be straightforward.
jQuery.ajax was not an issue, besides the need to use a Mixin to support
ember-fetch in the adapter.
My hope is that this will be resolved soon, either once this PR gets merged, or more broadly with how Ember will handle Mixins in the future with classes.
One note of caution—whilst this all works fine in application code after removing jQuery as a dependency I can imagine as lots of addons are currently still using jQuery it may still be a necessary dependency projects that use them (until the maintainers have also migrated away).
In this second part I’ve now gone deeper into the future way of writing Ember code. Taking a look at how microtasks will unlock native promise and elements of the run loop which will allow features like async/await to be used stress-free.
I feel like this will dramatically reduce some of the hidden complexity which can surface as developers progress with more complex Ember applications.
That day seems very close when articles like this one I wrote on registering waiters in async testing are no longer useful.
Additionally, it’s become clear to me now that using jQuery is definitely no longer obligatory and that thanks to the great testing story test driven development is much more a realistic proposition rather than idealistic goal.
Many of these things can already be tried out today, because the implementations are nearing completion. If we keep executing, a year from now we will take all these features for granted, and that will be wonderful.
— Ember 2018 Priorities by Edward Faulkner
Before working through these experiments I’d imagined that one post would be enough to cover what I’d hoped to—but that hasn’t turned out to be the case.
In fact, I still haven’t covered a few of the things which are, for me, some of the most important and exciting forthcoming features of Ember.
Maybe I should have covered each topic more briefly but my aim was to explain each point clearly enough so that I (and hopefully others too) could refer back to them as a basic reference, if needed.
That said I don’t want to leave it at this.
My next post is going to focus on using native npm imports, optimizing for filesize and performance (including service workers), and hopefully even how to use Fastboot (with rehydration).
I’d like to end this series by providing a finished demo app with the best of both worlds—a fast initial loading application but with rich functionality.
In the meantime I’d love to hear any comments or feedback on this—especially if you think I’ve missed something important or there is something which could be improved.