No matter how much experience you have with JavaScript, odds are you don't fully understand the language. As part of the "You Don't Know JS" series, this concise yet in-depth guide focuses on new asynchronous features and performance techniques--including Promises, generators, and Web Workers--that let you create sophisticated single-page web applications and escape callback hell in the process.
Like other books in this series, You Don't Know JS: Async & Performance dives into trickier parts of the language that many JavaScript programmers simply avoid. Armed with this knowledge, you can become a true JavaScript master.
With this book you will:
Explore old and new JavaScript methods for handling asynchronous programming Understand how callbacks let third parties control your program's execution Address the "inversion of control" issue with JavaScript Promises Use generators to express async flow in a sequential, synchronous-looking fashion Tackle program-level performance with Web Workers, SIMD, and asm.js Learn valuable resources and techniques for benchmarking and tuning your expressions and statements
Kyle Simpson is an Open Web Evangelist from Austin, TX, who's passionate about all things JavaScript. He's an author, workshop trainer, tech speaker, and OSS contributor/leader.
This book dives deep into various techniques for handling asynchronous operations in JavaScript. In particular the simplicity and drawbacks of callbacks are outlined with suggestions to address them as the cost of added code complexity. The chapter on promises is one of the best that I've read and walks through great examples of chaining and the power of composing. The chapter on generators focuses on modeling asynchronous code in a more synchronous manner. I was unconvinced and found the code examples hard to follow or reason about. The chapter briefly mentions the proposed ES7 async/await syntax which makes more sense to me and can be used today with the Babel transpiler. The final two chapters on performance and benchmarking felt like blog posts primarily linking to other resources and best practices. The callbacks and promises chapters are must reads while most of the rest can be skipped and definitely ignore the author's ubiquitous self promotion of his asynquence library.
الكتاب الرابع من سلسلة أنت لا تعرف جافاسكربت. وأظنه أصعب الكتب أو أكثرها غوصًا في التفاصيل التقنية.
الفصل الأول يعرض الفرق بين التنفيذ المتزامن، غير المتزامن، والتنفيذ المتواقت للكود في جافاسكربت. وأقصد بها على الترتيب:
Synchrony, Asynchrony, Concurrency.
الفصل الثاني يتحدث عن أقدم أساليب كتابة الكود غير المتزامن وهي دوال الردود Callbacks ويتوسع في شرح مشاكل ومساؤى هذا الأسلوب.
الفصل الثالث يتحدث عن دوال الوعود في جافاسكرتب Promises وهي تحل كافة مشاكل دوال الردود في كتابة كود غير متزامن. وأهمها معكوسية التحكّم والموثوقية.
الفصول الثلاثة الأولى مفيدة للغاية، وأنصح بقرائتها لجميع المبرمجين. مع بداية الفصل الرابع وحديثه عن دوال المولدات Generators تبدأ التفاصيل التقنية الدقيقة والحديث المتشعب. هناك إشارة عابرة إلى دوال async/await بحكم القدم النسبي للكتاب رغم أنها أحدث الدوال الأكثر شيوعًا وسهولة للاستخدام اليوم في تأليف كود غير متزامن.
الفصل الخامس والسادس مخصص للحديث عن كيفية قياس أداء البرامج ونصائح وأدوات متعلقة بذلك. الملحقين الأول والثاني لم أستطع إكمالهما حقًا وهي متعلقة بشرح مكتبة من تأليف الكاتب نفسه تُدعى asynquence
وسيكون لي وقفة لاحقة معها في قراءة ثانية للكتاب لاحقًا. إن وجدت لذلك فائدة مرجوة
“setTimeout(…) timers may not fire with perfect temporal accuracy. You’re guaranteed (roughly speaking) that your callback won’t fire before the time interval you specify, but it can happen at or after that time, depending on the state of the event queue.”
“Parallel Threading. It’s very common to conflate the terms “async” and “parallel,” but they are actually quite different. Remember, async is about the gap between now and later. But parallel is about things being able to occur simultaneously.”
“The most common tools for parallel computing are processes and threads. Processes and threads execute independently and may execute simultaneously: on separate processors, or even separate com-puters, but multiple threads can share the memory of a single process.”
“threaded programming is very tricky, because if you don’t take special steps to prevent this kind of interruption/interleaving from happening, you can get very surprising, nondeterministic behavior that frequently leads to headaches.”
“JavaScript never shares data across threads, which means that level of nondeterminism isn’t a concern.”
“setTimeout(…0) is not technically inserting an item directly onto the event loop queue. The timer will insert the event at its next opportunity. For example, two subsequent setTime out (… 0) calls would not be strictly guaranteed to be processed in call order, so it is possible to see various conditions like timer drift where the ordering of such events isn’t predictable. In Nodejs, a similar approach is process.next Tick(…). Despite how convenient (and usually more performant) it would be, there’s not a single direct way (at least yet) across all environments to ensure async event ordering.”
“A JavaScript program is (practically) always broken up into two or more chunks, where the first chunk runs now and the next chunk runs later, in response to an event. Even though the program is executed chunk-by-chunk, all of them share the same access to the program scope and state, so each modification to state is made on top of the previous state. Whenever there are events to run, the event loop runs until the queue is empty. Each iteration of the event loop is a tick. User inter-action, 10, and timers enqueue events on the event queue. At any given moment, only one event can be processed from the queue at a time. While an event is executing, it can directly or indirectly cause one or more subsequent events. Concurrency is when two or more chains of events interleave over time, such that from a high-level perspective, they appear to be running simultaneously (even though at any given moment only one event is being processed). It’s often necessary to do some form of interaction coordination between these concurrent “processes” (as distinct from operating system processes), for instance to ensure ordering or to prevent race conditions. These “processes” can also cooperate by breaking themselves into smaller chunks and to allow other “process” interleaving.”
“it was decided that the way to recognize a Promise (or something that behaves like a Promise would be to define something called a thenable as any object or function which has a then (…) method on it. It is assumed that any such value is a Promise-conforming thenable.”
“you should never rely on anything about the ordering/scheduling of callbacks across Promises. In fact, a good practice is not to code in such a way where the ordering of multiple callbacks matters at all. Avoid that if you can.”
“fundamental principle that Promises are immutable once resolved.”
“If you pass an immediate, non-Promise, non-thenable value to Promise. resolve(…), you get a promise that’s fulfilled with that value. In this case, promises p1 and p2 will behave identically”
“The most natural form of error handling for most developers is the synchronous try…catch construct. Unfortunately, it’s synchronous-only, so it fails to help in async code patterns”
“Promise.all([ … ]) expects a single argument, an array, consisting generally of Promise instances. The promise returned from the Promise.all([… ]) call will receive a fulfillment message (msgs in this snippet) that is an array of all the fulfillment messages from the passed in promises, in the same order as specified (regardless of fulfillment order).”
“Technically, the array of values passed into Promise.all(l … ]) can include Promises, thenables, or even immediate values. Each value in the list is essentially passed through Promise. resolve(…) to make sure it’s a genuine Promise to be waited on, so an immediate value will just be normalized into a Promise for that value. If the array is empty, the main Promise is immediately fulfilled.”
“A race requires at least one “runner,” so if you pass an empty array, instead of immediately resolving, the main race([…]) Promise will never resolve.”
“none ([ … ]) - This pattern is like all ([ … ]), but fulfillments and rejections are transposed. All Promises need to be rejected-rejections become the fulfillment values and vice versa. any ([ … ]) - This pattern is like all([ … ]), but it ignores any rejections, so only one needs to fulfill instead of all of them. first([ … ]) - This pattern is like a race with any ([ … ]), which means that it ignores any rejections and fulfills as soon as the first Promise fulfills. last([ … ]) - This pattern is like first([ … ]), but only the latest fulfillment wins.”
“The revealing constructor Promise(.) must be used with new, and must be provided a function callback, which is synchronously/ immediately called. This function is passed two function callbacks that act as resolution capabilities for the promise. We commonly label these resolve(…) and reject… )”
“reject(…) simply rejects the promise, but resolve(…) can either fulfill the promise or reject it, depending on what it’s passed. If resolve(…) is passed an immediate, non-Promise, non-thenable value, then the promise is fulfilled with that value. But if resolve(…) is passed a genuine Promise or thenable value, that value is unwrapped recursively, and whatever its final resolu-tion/state is will be adopted by the promise.”
“A shortcut for creating an already-rejected Promise is Promise. reject(… )”
“Promise.resolve(…) is usually used to create an already-fulfilled Promise”
“And remember, Promise. resolve(…) doesn’t do anything if what you pass is already a genuine Promise; it just returns the value directly.”
“Each Promise instance (not the Promise API namespace) has then (…) and catch(…) methods, which allow registering of fulfillment and rejection handlers for the Promise. Once the Promise is resolved, one or the other of these handlers will be called, but not both, and it will always be called asynchronously”
“then(…) and catch(…) also create and return a new promise, which can be used to express Promise chain flow control.”
“Promise.wrap(…) does not produce a Promise. It produces a function that will produce Promises.”
“The act of wrapping a callback-expecting function to be a Promise-aware function is sometimes referred to as “lifting” or “promisify-ing”.”
“As of ES6, the way to retrieve an iterator from an iterable is that the iterable must have a function on it, with the name being the special ES6 symbol value Symbol. iterator. When this function is called, it returns an iterator. Though not required, generally each call should return a fresh new iterator.”
“The purpose of yield-delegation is mostly code organization, and in that way is symmetrical with normal function calling.”
“The key benefit of generators related to async flow control is that the code inside a generator expresses a sequence of steps for the task in a naturally sync/sequential fashion. The trick is that we essentially hide potential asynchrony behind the yield keyword-moving the asynchrony to the code where the generator’s iterator is controlled. In other words, generators preserve a sequential, synchronous, blocking code pattern for async code, which lets our brains reason about the code much more naturally, addressing one of the two key drawbacks of callback-based async.”
“an environment like your browser can easily provide multiple instances of the JavaScript engine, each on its own thread, and let you run a different program in each thread. Each of those separate threaded pieces of your program is called a (Web) Worker. This type of parallelism is called task parallelism, as the emphasis is on splitting up chunks of your program to run in parallel.”
“To kill a Worker immediately from the program that created it, call terminate() on the Worker object”
“Inside the Worker, you do not have access to any of the main program’s resources. That means you cannot access any of its global variables, nor can you access the page’s DOM or other resources. Remember: it’s a totally separate thread. You can, however, perform network operations (Ajax, WebSockets) and set timers. Also, the Worker has access to its own copy of several important global variables/features, including navigator, loca tion, JSON, and applicationCache.”
“What are some common uses for Web Workers? • Processing intensive math calculations • Sorting large data sets. • Data operations (compression, audio analysis, image pixel manipulations, etc.) • High-traffic network communications”
“typed arrays like UintArray (see the ES6 & Beyond title of this series) are Transferables.”
“Shared Workers survive the termination of a port connection if other port connections are still alive, whereas dedicated Workers are terminated whenever the connection to their initiating program is terminated.”
“Single instruction, multiple data (SIMD) is a form of data parallel-ism, as contrasted to task parallelism with Web Workers, because the emphasis is not really on program logic chunks being parallel-ized, but rather multiple bits of data being processed in parallel.”
“asm.js is a label for a highly optimizable subset of the JavaScript lan-guage. By carefully avoiding certain mechanisms and patterns that are hard to optimize (garbage collection, coercion, etc.), asm.js-styled code can be recognized by the JS engine and given special attention with aggressive low-level optimizations.”
“Luckily, smart folks like John-David Dalton and Mathias Bynens do understand these concepts, and wrote a statistically sound benchmarking tool called Benchmark.js. So I can end the suspense by simply saying: “just use that tool.””
“What this boils down to is that testing not real code gives you not real results. If possible and practical, you should test actual real, nontrivial snippets of your code, and under as best of real conditions as you can actually hope to. Only then will the results you get have a chance to approximate reality.”
“jsPerf. It uses the Benchmark.js library we talked about earlier to run statistically accurate and reliable tests, and makes the test on an openly available URL that you can pass around to others.”
“jsPerf.com is a fantastic website for crowdsourcing performance benchmark test”
Quite technical, not at all light, very interesting read. Although understanding promises and generators is quite handy, the last part about advanced patterns is one of those things that I'm not sure when I'll end up using.
Still, while I personally appreciate knowing stuff, without worrying too much about when I'll find that knowledge useful, some more pragmatic folks will probably skip those parts (apendixes).
The chapter about promises is a little too preachy, promising that they will save us from callbacks...only to in the end, get to creating code that requires maybe a little too much mind bending.
Also, now it's december 2018. The async/await keywords made it to the language (maybe?...not sure..I write python most of the time). Many of the patterns in the book would be obsoleted by these new keywords. Those make async code look waaay more sync. Somehow I already met the async/await keywords in python and took them for granted. Without those, the world is a very dark place indeed, as illustrated by the many patterns and "workarounds" in this book.
All in all, if you appreciate perspective on promises and generators, this is a good book, though a little outdated.
O yeah, there is a random chapter here about performance... it was ok, but what's up with that? It was probably worth writing another book on that (maybe even shorter), but the author maybe wasn't in the mood for so much research. I can't blame the guy, there is a lot of information in the books in this series, after 6 books, the guy is exhausted :p (or maybe the publisher didn't approve? Dunno, but the chapter was random. He could have written about the performance of async operations I guess, but that was not the case :p
Good book! Discard the preachiness, and you'll learn lots of things
I have never imagined that there are so many concerns not with callbacks, but regarding promises as well.
Wonderful book on handling async requests via callbacks, promises and handling them via generators. Kyle looks ahead a bit into ES7 async\await features.
Last two chapters cover web performance, from general topics: Web Workers, SIMD, asm.js, to very specific ones: benchmarking pieces of js code, figuring out crucial path. I will definitely take a look at https://benchmarkjs.com
La primera mitad se puede saltar si se entiende bien como funcionan las promesas, la segunda se pone mas interesante con los generadores y performance.
A fantastic exploration of what "async" means in the context of JavaScript. I was amazed at the depth of explanation provided especially for the Promises chapter. It is a gold mine in my opinion, one that I expect to be returning to again and again.
The author's take on Generators is pretty interesting. Though I must confess, after a while, it started going a little above my head. This only means that the text is dense and needs re-reading. This also makes me think how much of this can I apply in my day-job. Considering the goal of keep code readable/simple, I am not very sure I will be using Generators anytime soon. Async/await looks fantastic and will certainly be useful in Node.js based environments.
I expect Promises to be the bread and butter of all async code that I write, at least for the next year or so. I am grateful to Kyle for the fantastic content he has provided in this area.
Overall a good read, something that makes you mildly uncomfortable, but just enough so you keep pressing into more of the language.
Clear and easy to understand, this has helped me make sense of the often murky world of promises and generators.
It's very information dense but I found it easier to get to grips with by reading through a chapter and then going back and trying out the supplied code for myself.
The performance chapters didn't feel as in-depth as the rest of the book but they did cover a few little things that the JavaScript engine will do to your code without you knowing (eg unrolling recursion for you if it thinks a loop will run faster) and things that you shouldn't spend time worrying about (--x or x--). They also went into how to use (and not use) benchmarking tests for checking your own code.
I must admit I got a bit lost on the last appendix - advanced async patterns - but I think that's because I haven't had much real-life practice of the basics yet.
This book has massively improved my understanding and use of async JavaScript code. It's one that I will be adding to the limited collection I keep on my desk.
The most interesting thing today is that I got one question in my interview about Promise and it was covered in this book. A few things from the top of my mind: 1. Callbacks are no good, use them sometimes and avoiding nest them. For many async task, try using Promise. 2. Promise tends to swallow errors so use it with async/await 3. Optimization my code is more complicated than other devs suggest. Using jsperf.com or benchmarkjs to test my optimzation. There are more to this book that I have yet put into my mind but I don't have any plan to reread this one in foreseeable future. The appendixes are about the author library asynquence which I guiltily skipped since I don't have any intention to take a loot at it. For the 2 months, I think I will just focus on Promise and async/await function. Btw sorry generator function for misunderstanding you. You are the precursor for the new async/await (since 2014 I guess)
Every book in this series is a must-read for a Javascript dev. This one does not fail to deliver. The reason I choose to read this book is to learn more about how aysnc works in JS. I never really mentally grasped ASYNC with full confidence even though I've been using it for over 10 years. I would need to google the best approach for addressing deadlocks or race conditions.
This book definitely helped gave me a much fuller understanding of async. All the issues with callback, not just callback hell... why generators are good. Some subtle nuances with promises I had never considered before.
You should read this book because it is asy to read and understand. It covers the fundamentals so you will understand and you can design async solutions with a lot more confidence
This is the worst book I have read in my life so far.
It's about 5 times more verbose than it needs to be, making it clear that the entire series actually could have been a single book rather than a series... but gotta make bank right?
Besides the verbosity the author jumps back and fourth referencing both past and future chapters as well as repeating concepts over and over and over... The chapter on promises alone spans around 70 pages and could have honestly been compacted to about 20 or less.
This book is a waste of time and money, god I even blocked the author on Twitter just so that I never have to ever read another word from him again. Every minute was torture and I'm glad it's over.
This one seemed to me not as useful as previous ones from the series. But, still, it's rather useful. It contains a great explanation about what Promises is and why they were included in js. But apart from it, the book contains chapters about topics related to concurrency itself but not to JavaScript itself. I didn't find it useful, since I am quite familiar with the concept.
Also, the book contains a chapter about Generators and I must confess I didn't get it. It's not clear what problems they solve and why I need them.
To conclude, my advice is to read the first three chapters of the book. The others you can read on your own risk)
El más complejo de la serie sin duda. Tuve que regresar a él unas tres veces porque estoy tonto para entender bien el concepto de programación asíncrona. Al final se cumple el principio de que la programación solo se aprende practicando, y después de algunas horas experimentando con promesas, pude terminar el libro.
Al ser una edición vieja, ya hay tecnologías que facilitan mucho las tareas que el libro propone. Sin embargo, la raíz de los conceptos sigue siendo la misma, y la manera en que son explicados aquí son lo que puede aportar valor a cualquier programador que le dé una checada.
Amazing book if you want to understand how asynchronicity (or the illusion of asynchronicity) in JavaScript works. Kyle has a unique way of explaining deep technical CS concepts in a simple and straightforward manner. He lays down the differences between concurrency, serialism and parallelism and then use those differences to explain the JS Event loop and then goes into the technicalities of implementation using callbacks, promises, and generators. Finally, he gives some overview of assessing performance and benchmarking.
I really liked building an understanding for promises and async/await in javascript. One thing that I had never seen before was generators which is the underlying magic behind asynchronous programming in javascript. It was cool to understand that better. The performance aspect of the book could have been more fulfilling but I guess if you're using javascript you probably don't care that much about performance anyway.
This whole series is awesome. Having read several JS books, it was nice to have a really comprehensive technical treatment on these topics. These books read really well, and somehow manage to be engaging at the same time as being very thorough.
One thing I really like about this book, is that since it is open-sourced and available on GitHub, I can easily reference it when any questions come up about these topics.
Callbacks, promises and generators. All things asynchronous. No reservations about the quality, but it was a bit boring. Among the books from the YDKJS series by Simpson, even though async operations is are hugely important in frontend programming, this one I liked probably the least and likely will not return to it and will use other resources for this topic. I skipped the addendums about asynquence library authored by Simpson, because it did not seem relevant anymore.
The last chapter on performance is a complete dud which could be summarized in a single paragraph. Some of the chapters are overtly long but still exhaustive so 4 stars unless I find a better book on this topic.
The first appendix was unnecessary (perhaps the second one as well), the Promise's chapter did get repetitive (but it was still good), and I wish he had gone deeper into performance. Still not a bad book though, worth reading.
This book ended up more low level than I had expected. Coming in without much of an understanding of generators and async/await, I ended up having to consult outside sources more than I'd have liked, just to be able to follow along with what the writer was talking about.
All the books in the series are quite verbose - over-explanation with analogies doesn't always make it easy to understand concepts. "Async & Performace" title doesn't get concurrency and parallelism right. Rest, it does do a good job of explaining JS's quirkiness.
I don't know why I didn't read this book earlier, for weeks I've been lost with all the "Async-Await" tech talks and now this book, eloquently written offers a clear and consice explanation.
The book itself is good. The only the part I didn't like was about the asyncquence library. I felt it was out of the scope of JavaScript core features. Apart from this book is amazing.
One of the best resources for learning the ins and outs of JS asynchronous programming and Promises. Some really great insight about JS performance and benchmarking too!
The best book about javascript I've read in which concerns to async and performance! Learned a lot of new things I didn't know and didn't find in another place.