(Ebook) TypeScript High Performance by Ajinkya Kher ISBN 9781785288647, 1785288644 All Chapters Instant Download
(Ebook) TypeScript High Performance by Ajinkya Kher ISBN 9781785288647, 1785288644 All Chapters Instant Download
https://ebooknice.com/product/biota-grow-2c-gather-2c-cook-6661374
ebooknice.com
https://ebooknice.com/product/typescript-handbook-
typescript-4-7-44980036
ebooknice.com
https://ebooknice.com/product/typescript-handbook-
typescript-4-8-45950316
ebooknice.com
https://ebooknice.com/product/typescript-handbook-
typescript-4-8-46499030
ebooknice.com
(Ebook) Principles of High-Performance Processor Design: For High
Performance Computing, Deep Neural Networks and Data Science by
Junichiro Makino ISBN 9783030768706, 3030768708
https://ebooknice.com/product/principles-of-high-performance-
processor-design-for-high-performance-computing-deep-neural-networks-
and-data-science-34095162
ebooknice.com
https://ebooknice.com/product/high-performance-python-42370716
ebooknice.com
https://ebooknice.com/product/python-high-performance-6781574
ebooknice.com
https://ebooknice.com/product/high-performance-habits-48256236
ebooknice.com
https://ebooknice.com/product/julia-high-performance-11117298
ebooknice.com
TypeScript High Performance
Ajinkya Kher
BIRMINGHAM - MUMBAI
TypeScript High Performance
Copyright © 2017 Packt Publishing
All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or
transmitted in any form or by any means, without the prior written permission of the
publisher, except in the case of brief quotations embedded in critical articles or reviews.
Every effort has been made in the preparation of this book to ensure the accuracy of the
information presented. However, the information contained in this book is sold without
warranty, either express or implied. Neither the author, nor Packt Publishing, and its
dealers and distributors will be held liable for any damages caused or alleged to be caused
directly or indirectly by this book.
Packt Publishing has endeavored to provide trademark information about all of the
companies and products mentioned in this book by the appropriate use of capitals.
However, Packt Publishing cannot guarantee the accuracy of this information.
ISBN 978-1-78528-864-7
www.packtpub.com
Credits
I am impressed by how much ground Ajinkya has covered in this book. Given his solid
background in full-stack software development, experience working with real-time
systems, and the desire to learn and grow along the way, the polished outcome in the form
of this book is not surprising. Ajinkya has truly brought his knowledge and insights to the
readers in an accessible manner and has let them in on the winning secrets that he has
leveraged in both professional settings and while triumphing in multiple Hackathons.
As a passionate technologist, fueled engineer, and creative problem solver, I have been a
witness and part of this evolution. I started using JavaScript in 2001 and have thoroughly
enjoyed the evolution since then. I enjoy the quirks of the language and the tiny things I’ve
spent hours trying to debug. I used to code in Notepad and would spend the proverbial 8
hours searching for a misspelled variable and massaging the bruises on my forehead from
the wall. I enjoy listening to everyone’s unique story about how they discovered that the
parseInt() function defines and documents two parameters, with the second being the radix
and probably the most frustrating parameter as it does not default to the expected value of
10.
We all have those unique yet similar stories. With TypeScript, we will save our children
from those headaches and hopefully reduce their chronic traumatic encephalopathy from
continuously beating their head against your basement wall. I have dabbled with
technologies on personal projects and I have worked for some of the biggest companies in
the world, including Microsoft, Siemens, Goldman Sachs, Deloitte, AT&T, and Coca-Cola.
With that experience, I hope that some of that can be shared with you as a reader of this
book.
If you are just beginning to venture into JavaScript or TypeScript, or if you’re a seasoned
veteran like me, you have something to gain from these pages. In my years of development
and consulting, I have never seen someone as passionate about learning tooling and
languages as Ajinkya. I worked with him when he first ventured into frontend development
with AngularJS.
The evolving world can be a scary place for most developers. This book has been designed
and is intended to allow you to smoothly transition from JavaScript to TypeScript, which is
why I highly recommend every JavaScript and TypeScript developer reads it cover to cover.
I recommend you read each section with an open mind and ask yourself questions or
consider reaching out to and engaging in forums, the publishing company, or industry
experts.
Congratulations on taking the first step toward the future of JavaScript, and smile while
you read this book!
Brian O’Connor
He loves getting his hands dirty with the latest and the greatest technologies out there. In
his free time, you can find him winning Hackathons, building mobile applications, and
lifting weights. He has been playing tennis for more than a decade and has been an ardent
fan of cricket and Sachin Tendulkar since childhood, his weekends are thus often spent
playing these two sports. He also likes to practice and read about spirituality and
philosophy whenever he can.
Check out his latest podcast Building Modern Web Applications using
React/Redux/Angular2/RxJs on YouTube and you can also follow him on LinkedIn.
Acknowlegement
I would like to express my gratitude to several people who have helped me through the
journey of this book. I would like to begin with my friends at Packt Publishing–-Sonali,
Kinnari, Vibhuti, and Zeeyan, who were of great help right from laying out the scope of the
book to offering comments, proofreading, and editing the chapters, all of which, I’m sure,
resulted in enhancing the quality of the book.
I would like to thank Brian and Maria for their generous contributions to this book. Both
Brian and Maria helped proofread the book and offered great feedback and encouragement.
I would like to specifically thank Brian for his invaluable contributions to Chapter 8, Build
and Development Strategies for Large-Scale Projects of this book.
I would like to thank Raji, who has constantly encouraged me to keep going and complete
this book. I would also like to thank my friends at work who encouraged me in the writing
process.
I would like to thank my family–-my mom, my dad, and my sister, Anushka, for their
invaluable and sincere feedback, encouragement, and most importantly, their patience
throughout the process. My parents were on a vacation here in Seattle as I was working
toward the completion of this book. They were very cheerful and supportive despite all the
time it took me away from them. This book wouldn’t have been complete without their
support.
Lastly, I would like to thank everyone who has helped shape me over the years and put me
in a position to share my insights and experience with you all in the form of this book.
About the Reviewer
Andrew Leith Macrae first cut his programming teeth on an Apple IIe, poking bytes into
the RAM. Over the years, he has developed interactive applications with Hypercard,
Director, Flash, and more recently, Adobe AIR for mobile. He has also worked with HTML
since there was HTML to work with and is currently working as a senior frontend
developer at The Learning Channel (www.tsc.ca), using Angular 4 with Typescript.
He is convinced that TypeScript is the future of JavaScript, bringing the structure and
discipline of strongly typed object-oriented language to facilitate efficient, intentional
coding for the development of large-scale applications for the Web.
You can find out more about Andrew or contact him at www.adventmedia.net.
www.PacktPub.com
For support files and downloads related to your book, please visit www.PacktPub.com.
Did you know that Packt offers eBook versions of every book published, with PDF and
ePub files available? You can upgrade to the eBook version at www.PacktPub.com and as a
print book customer, you are entitled to a discount on the eBook copy. Get in touch with us
at service@packtpub.com for more details.
At www.PacktPub.com, you can also read a collection of free technical articles, sign up for a
range of free newsletters and receive exclusive discounts and offers on Packt books and
eBooks.
https://www.packtpub.com/mapt
Get the most in-demand software skills with Mapt. Mapt gives you full access to all Packt
books and video courses, as well as industry-leading tools to help you plan your personal
development and advance your career.
Why subscribe?
Fully searchable across every book published by Packt
Copy and paste, print, and bookmark content
On demand and accessible via a web browser
Customer Feedback
Thanks for purchasing this Packt book. At Packt, quality is at the heart of our editorial
process. To help us improve, please leave us an honest review on this book's Amazon page
at https://www.amazon.com/dp/1785288644.
If you'd like to join our team of regular reviewers, you can e-mail us at
customerreviews@packtpub.com. We award our regular reviewers with free eBooks and
videos in exchange for their valuable feedback. Help us be relentless in improving our
products!
I dedicate this book to my mom, who is my first teacher, friend, and mentor. She taught me the
alphabet as a child, and she's still the first one to update me on the latest technological innovations.
She has dedicated her life towards my all-round growth and her contributions to my life are
incalculable.
Table of Contents
Preface 1
Chapter 1: Efficient Implementation of Basic Data Structures and
Algorithms 7
Strings 8
String concatenation 9
String replacement 12
Classes and interfaces 15
Loops and conditions 20
Arrays and sorting 26
Operators 30
Summary 33
Chapter 2: Variable Declarations, Namespaces, and Modules 34
Variable declarations 34
The var declarations 36
The let declarations 39
The const declarations 41
Namespaces and modules 41
Modules 45
Summary 48
Chapter 3: Efficient Usage of Advanced Language Constructs 49
Arrow functions 50
Mixins 55
Declaration merging 59
Triple-slash directives 64
Answers to declaration merging questions 67
Summary 71
Chapter 4: Asynchronous Programming and Responsive UI 72
Fundamentals of asynchronous programming and event loop 74
Synchronous data fetch 75
Asynchronous data fetch 76
Event loop 77
Callbacks 87
Callback Hell 93
Promises 95
Async and await 103
Summary 112
Chapter 5: Writing Quality Code 113
Unit tests 114
Static code analysis with TSLint 129
Setting up TSLint for your project 130
Editing default rules 136
Extending TSLint rules 138
TSLint VSCode Extension 139
Summary 142
Chapter 6: Efficient Resource Loading - Critical Rendering Path 143
Resource delivery across the internet 144
Optimizing the critical rendering path 148
Optimization 1 - render blocking CSS 152
Optimization 2 - render blocking JS 154
Non-blocking UI 157
Massive data downloads 157
Massive data uploads 161
Summary 162
Chapter 7: Profile Deployed JS with Developer Tools and Fiddler 163
Chrome Developer Tools 164
Memory profiling 164
Latency and computation time profiling 169
The Network tab 174
Fiddler 180
Summary 188
Chapter 8: Build and Deployment Strategies for Large-Scale Projects 189
Building locally 190
Grunt 190
Gulp 191
MSBuild 192
Continuous integration (CI) 193
The process 194
Jenkins 196
Bamboo 196
Continuous delivery (CD) 196
Chef 198
[]
Puppet 198
Containerization 198
Docker 199
Serverless applications 199
Testing 199
Summary 200
Index 201
[]
Preface
Over the last two decades, JavaScript has grown from enabling developers to perform
simple interactions with in-browser HTML to being the core of enterprise applications, both
frontend and backend. This success has become more apparent with the advent and
creations of NodeJS, Cordova, Ionic, and serverless frameworks, all of which have adopted
and support TypeScript. This growth, coupled with the ever-increasing demand for
complex and performant JavaScript, has fueled the need for stricter typing, structures, and
code decoupling.
With this evolution, it is necessary for learning to take place for newbies and gurus alike.
This book has been designed to walk through various topics of the language, building into
meaningful constructs to help you, as a TypeScript developer, build scalable, efficient, and
maintainable applications from the first line of code. We start by walking you through
language structure and terminology, continue through optimizing your code to load
quickly and fine-tune performance, and wrap up with a discussion on building and
deploying applications for large-scale and enterprise applications.
TypeScript is here to stay and will be looked back upon as the next iteration of JavaScript
just as its predecessors, such as Prototype, jQuery, Dojo, and Mootools, were. This book will
walk you through the language and will explain how to write efficient enterprise
TypeScript to scale.
Chapter 2, Variable Declarations, Namespaces, and Modules, describes the distinction and
correct usage of variable declarations. It also describes code organization strategies, namely
leveraging namespaces and modules.
Chapter 3, Efficient Usage of Advanced Language Constructs, covers several different language
constructs in TypeScript. It explains how to use them, the scenarios in which to use each
construct, and their efficient usage.
Chapter 4, Asynchronous Programming and Responsive UI, is a deep dive into the world of
asynchronous programming. We walk you through the massive performance hits your
application can take if not built correctly, and we discuss strategies and tips for efficient
coding.
Chapter 6, Efficient Resource Loading - Critical Rendering Path, introduces the critical
rendering path and the steps involved in the process of loading a web application. We
discuss strategies for quick and non-blocking resource loading to produce a highly
responsive and performant application load.
Chapter 7, Profile Deployed JS with Developer Tools and Fiddler, introduces the concept of
profiling and the tools available. We compare the performance results of quality code
written with the help of TSLint and compare it to poorly written TypeScript code.
[2]
Preface
Basic knowledge of TypeScript and some experience using JavaScript are prerequisites for
this book.
Conventions
In this book, you will find a number of text styles that distinguish between different kinds
of information. Here are some examples of these styles and an explanation of their meaning.
Code words in text, database table names, folder names, filenames, file extensions,
pathnames, dummy URLs, user input, and Twitter handles are shown as follows: "Since the
text variable was not previously defined, the log output will now display a compilation
error." A block of code is set as follows:
// const tests
function constTest(): () => number {
const x: number = 16;
x = 4; // Left-hand side of assignment expression cannot be
a constant
return function innerFunction(): number {
x++; // the operand of an increment or decrement operator
[3]
Preface
cannot be a constant
return x;
}
}
When we wish to draw your attention to a particular part of a code block, the relevant lines
or items are set in bold:
[default]
exten => s,1,Dial(Zap/1|30)
exten => s,2,Voicemail(u100)
exten => s,102,Voicemail(b100)
exten => i,1,Voicemail(s0)
New terms and important words are shown in bold. Words that you see on the screen, for
example, in menus or dialog boxes, appear in the text like this: "Let's take a look at the
Network tab of the Developer Tools."
Reader feedback
Feedback from our readers is always welcome. Let us know what you think about this
book-what you liked or disliked. Reader feedback is important for us as it helps us develop
titles that you will really get the most out of. To send us general feedback, simply e-mail
feedback@packtpub.com, and mention the book's title in the subject of your message. If
there is a topic that you have expertise in and you are interested in either writing or
contributing to a book, see our author guide at www.packtpub.com/authors.
[4]
Preface
Customer support
Now that you are the proud owner of a Packt book, we have a number of things to help you
to get the most from your purchase.
1. Log in or register to our website using your e-mail address and password.
2. Hover the mouse pointer on the SUPPORT tab at the top.
3. Click on Code Downloads & Errata.
4. Enter the name of the book in the Search box.
5. Select the book for which you're looking to download the code files.
6. Choose from the drop-down menu where you purchased this book from.
7. Click on Code Download.
Once the file is downloaded, please make sure that you unzip or extract the folder using the
latest version of:
[5]
Preface
Errata
Although we have taken every care to ensure the accuracy of our content, mistakes do
happen. If you find a mistake in one of our books-maybe a mistake in the text or the code-
we would be grateful if you could report this to us. By doing so, you can save other readers
from frustration and help us improve subsequent versions of this book. If you find any
errata, please report them by visiting http://www.packtpub.com/submit-errata, selecting
your book, clicking on the Errata Submission Form link, and entering the details of your
errata. Once your errata are verified, your submission will be accepted and the errata will
be uploaded to our website or added to any list of existing errata under the Errata section of
that title. To view the previously submitted errata, go to
https://www.packtpub.com/books/content/support and enter the name of the book in the
search field. The required information will appear under the Errata section.
Piracy
Piracy of copyrighted material on the Internet is an ongoing problem across all media. At
Packt, we take the protection of our copyright and licenses very seriously. If you come
across any illegal copies of our works in any form on the Internet, please provide us with
the location address or website name immediately so that we can pursue a remedy. Please
contact us at copyright@packtpub.com with a link to the suspected pirated material. We
appreciate your help in protecting our authors and our ability to bring you valuable
content.
Questions
If you have a problem with any aspect of this book, you can contact us at
questions@packtpub.com, and we will do our best to address the problem.
[6]
Efficient Implementation of
1
Basic Data Structures and
Algorithms
One of the most important things to achieve optimal performance with any language is to
understand the correct usage of the data types and the constructs it offers. If leveraged
optimally, these features can help in producing a robust and high performance application,
but if leveraged in a non-optimal fashion, the same features can adversely impact the
overall performance and usability of the end product.
Let's take a look at the performance impact with the help of the following basic constructs,
operations, and data structures:
Strings
Let's start by taking a look at strings. In TypeScript, you can create a string in one of the
following ways:
var test1: string = 'test string';
For all practical purposes, you would almost always use the first way to work with strings.
The only difference between the two is that string is a literal type and a preferred way to
declare strings in TypeScript. String is an object type, which is essentially a wrapper object
around the string. From a performance standpoint, literal types tend to perform better than
object types. We can confirm this by running a simple code snippet as mentioned in the
following code snippet:
function createString_1(): string {
return `Lorem Ipsum is simply dummy text of the printing and
typesetting industry. Lorem Ipsum has been the industry''s
standard dummy text ever since the 1500s, when an unknown
printer took a galley of type and scrambled it to make a type
specimen book. It has survived not only five centuries, but also
the leap into electronic typesetting, remaining essentially
unchanged.It was popularised in the 1960s with the release of
Letraset sheets containing Lorem Ipsum passages, and more
recently with desktop publishing software like Aldus PageMaker
including versions of Lorem Ipsum.`;
}
[8]
Efficient Implementation of Basic Data Structures and Algorithms
time2 = Date.now();
console.log('Time difference (createString_2): ', time2 - time1);
The preceding code snippet creates a long string (the famous filler text mostly used as a
placeholder on visual web elements) using the preceding described two ways.
Now, let's take a look at the results of executing the preceding code snippet:
As you can see from the results, the literal type string does behave slightly better. The
creation of the string, however, is not the most impacting operation that would affect your
application. Let's take a look at some classic string manipulation operations.
String concatenation
Let's start with string concatenation. Take a look at the following code snippet:
function createString(): string {
return `Lorem Ipsum is simply dummy text of the printing and
typesetting industry. Lorem Ipsum has been the industry''s
[9]
Efficient Implementation of Basic Data Structures and Algorithms
time2 = Date.now();
console.log('Time difference: ', time2 - time1);
The preceding snippet contains a simple function createString, which returns a long
string, precisely 617 characters long. We append this string to itself 40,000 times. In the first
loop, s1 does so by calling s1.concact(createString()) as many times, and in the
second loop, s2 does so by calling s2+= createString() as many times. This is just a
shorthand for s2 = s2 + createString().
When you analyze these loops, how long do you think they took to complete execution?
Did one substantially outperform the other? Or, do you think they're just two different
ways to append a string to itself, and has no impact on performance? Well, here are the
results:
[ 10 ]
Efficient Implementation of Basic Data Structures and Algorithms
The preceding results are an average of five runs. As you can clearly see, Loop 1
outperforms Loop 2 massively.
Just to understand how massive the impact on the end result would be, consider the
following scenario. Consider a social web application, which when the user starts on his/her
end loads the entire friend/contact list and the entire conversation history with each
contact. Hypothetically, assume that the user has 100 contacts, and with each contact he/she
has 10 conversations. Let's further assume each conversation to be essentially the preceding
string in our example appended to itself 40,000 times. Using our preceding results
(considering Chrome as the web browser), with an inefficient implementation of string
concatenation the page load time would be 100 * 10 * 60 milliseconds = 60,000 milliseconds =
60 seconds or 1 minute. Now, that's a really long time the user has to wait before the
application becomes functional. Such sluggishness can greatly impact the application's
usability and user engagement.
As opposed to this, if the user was to load the same application with the efficient string
concatenation technique, the user wait time would be 100 * 10 * 7 = 7,000 milliseconds = 7
seconds, which is not quite that bad.
If you're starting to appreciate the powers of efficient implementation, we're just getting
started. The time performance isn't even the critical impact factor. The resource that is
greatly impacted is memory!
However, when you do s2+= createString(), you're essentially creating a new object
each time. If s2 was pointing to a memory block which occupies x bytes, now after one call
to s2+= createString(), it is pointing to a new memory block which occupies x + x =
2x bytes. Thus, at each step, the total memory consumption is greatly increased.
After 40,000 such invocations, the first loop will result in total memory consumption of
40,000 * x bytes, whereas the second loop will result in total memory consumption of x + 2x
+ 3x + ... + 40,000 * x bytes = 800, 020 * x bytes. As you can see, way greater memory is
consumed by the second loop.
Running some tests, it is observed that on Chrome, the shallow size occupied by the
concatenated string during the execution of the first loop is 802, 160 bytes, or ~0.8 MB. The
shallow size occupied by the concatenated string during the execution of the second loop is
8, 002, 160 bytes, or ~8 MB.
[ 11 ]
Efficient Implementation of Basic Data Structures and Algorithms
The implications of this are dastardly, and the user can experience application crashes and
freezes due to memory overload, which would lead to poor user experience and if not
immediately corrected, very soon zero usability and lost business.
String replacement
Take a look at the following code snippet:
function createString(): string {
return `Lorem Ipsum is simply dummy text of the printing and
typesetting industry. Lorem Ipsum has been the industry''s
standard dummy text ever since the 1500s, when an unknown
printer took a galley of type and scrambled it to make a type
specimen book. It has survived not only five centuries, but
also the leap into electronic typesetting, remaining
essentially unchanged. It was popularised in the 1960s with the
release of Letraset sheets containing Lorem Ipsum passages, and
more recently with desktop publishing software like Aldus
PageMaker including versions of Lorem Ipsum.`;
}
let baseString: string = createString();
const replacementCharacter: string = '|';
let time1: number = Date.now();
for (let i = 0; i < 50000; i++) {
baseString.split(' ').join(replacementCharacter);
}
let time2: number = Date.now();
console.log('Time difference (SplitJoin): ', time2 - time1);
time1 = Date.now();
for (let i = 0; i < 50000; i++) {
baseString.replace(/ /g , replacementCharacter);
}
time2 = Date.now();
console.log('Time difference (Replace_w_RegExp): ', time2 -
time1);
In the preceding code snippet, we start with the same base string as in previous examples.
Here, we have the objective of replacing every whitespace with the pipe character ('|').
For example, if the base string were "High Performance TypeScript", after applying our
replace logic, the resultant string would be "High|Performance|TypeScript".
[ 12 ]
Efficient Implementation of Basic Data Structures and Algorithms
Now, this string has a total of 127 whitespaces. We loop over the base string and perform
this replacement a total of 50,000 times. Let's understand the following two different
replacement options we are leveraging:
SplitJoin: Let's take a look at the following replacement option code snippet:
baseString.split(' ').join(replacementCharacter);
Let's split this into two pieces to better understand how this works, such
as split and join:
split: This method splits the string into an array of strings by separating
the string into substrings, as specified by an optional splitter character. Here,
we are using the whitespace (' ') as the splitter character. So, after we
apply baseString.split(' '), baseString is split into a string array of
length 128.
join: This method joins or combines all elements of a string array into a
string, as specified by an optional combiner character. Here, we specify the
pipe ('|') as the combiner character. Thus, the result
of baseString.split(' ').join('|') is a resultant string of the same
length as the base string (617 characters), with all the whitespaces replaced
by the pipe character.
Replace with RegEx: Let's take a look at the following replacement option code
snippet:
The replace method returns a new string with some or all matches of a pattern
replaced by a replacement character. We again choose the pipe character as the
replacement character, and the pattern we choose is a regular expression '/ /g'.
We specify a RegEx by enclosing it within the forward slash character ('/').
Here, we specify a white space as the RegEx.
[ 13 ]
Efficient Implementation of Basic Data Structures and Algorithms
If you were to analyze the two methods, you would note that in the SplitJoin method you
perform two passes around the input string -- first to break it down into smaller chunks,
and then to combine those chunks back into a whole string. This would involve as many
string concatenations as the number of chunks it got split into in the first place. The Replace
with RegEx options seems to take one pass around the input string, creating a new string
copy, character by character, looking for a pattern match along the way and replacing it
with the replacement character. An educated guess would be that the Replace with
RegEx option has a better performance.
Let's take a look at the results to find out! Note that these are a result of 127 replacements on
a 617 character long string, done 50,000 times:
As we predicted, the Replace with the RegEx method outperforms the SplitJoin method.
The difference between the two methods is more significant on IE and Edge. In terms of
real-world usage, string replacement is even more widely used than concatenation. Any
web/mobile application with a frontend framework that works with multiple backends, or
even a single backend, can run into the string replacement scenarios where data
interpretation across different systems varies and there's a need to replace some strings to
convert it into a format that the current system can understand. If done inefficiently, the
results could once again lead to a slower/sluggish UI rendering, higher network latencies,
incapability in using the application's full feature set due to the slower performance making
the application unusable and gives you a poor user experience overall.
As you can see, efficient implementation of basic data type manipulations have a far
reaching impact on the performance and usability of an application. Let's look at some other
data structures and constructs.
[ 14 ]
Efficient Implementation of Basic Data Structures and Algorithms
These are the basics which you must already be familiar with. Instead of introducing some
simple examples of class and interface declaration, let's deep dive into an advanced usage
scenario, very close to how real-world modern web/mobile applications are structured. Pay
close attention to the following problem statement.
Let's assume we are a vendor company for another firm, lets say XYZ. Now, XYZ contacts
us and asks us to implement Social Network Feed Generator (SNFG). XYZ is building an
application to combine social network feed from all possible social networks, and displays
this aggregated feed to it's users. Let's assume a scenario in which a single universal key or
token that can authenticate a user against all of his/her social networks (let's not worry
about the security at this moment, as we are not trying to understand cryptography here!).
XYZ plans to pass us this key for it's users, and in return, wants an aggregated feed based
on several different criteria such as most recent updates, most popular updates, and so
on. Now, our job is simple --to provide an API to XYZ that it can use in it's application.
Let's get started building SNFG in an object-oriented way, making it extensible for future
updates. Take a look at the following code snippet:
// publicly accessible
export enum FeedStrategy { Recent, Popular, MediaOnly };
// internal
enum SocialMediaPlatform { Facebook, Instagaram, Snapchat,
Twitter, StackOverflow };
// publicly accessible
export interface IFeed {
platformId: SocialMediaPlatform;
content: string;
media: string
}
// publicly accessible
export interface IFeedGenerator {
getFeed(limit?: number): IFeed[];
}
// internal
[ 15 ]
Efficient Implementation of Basic Data Structures and Algorithms
// internal
class PopularFeedGenerator implements IFeedGenerator {
private authenticate(universalKey: string): void {
// autheticate user identity
}
/* you can have as many classes as you desire, or you can also
combine multiple feed fetching algorithms into single class */
// publicly accessible
export function FeedGeneratorFactory(feedStrategy: FeedStrategy,
universalKey: string): IFeedGenerator {
let feedGenerator: IFeedGenerator = null;
switch (feedStrategy) {
case FeedStrategy.Recent: {
feedGenerator = new RecentFeedGenerator();
break;
}
case FeedStrategy.Popular: {
[ 16 ]
Efficient Implementation of Basic Data Structures and Algorithms
We design a module called Feeder (we will be looking at modules and namespaces in
closer details in the next chapter). Within this module, we build the crux of our SNFG. The
idea is that XYZ can use the exported members (publicly accessible) of this module to
achieve its objective. Let's take a look at the exported members of Feeder in the following
code snippet:
export enum FeedStrategy { Recent, Popular, MediaOnly };
The most important exported function is FeedGeneratorFactory. XYZ can call this
function with it's desired FeedStrategy (which is also exposed as an enum), and
universalKey for the user it wishes to access the feed of. With this information,
what FeedGeneratorFactory does is completely abstracted. This function returns an
interface type IFeedGenerator. This is all that the developers of XYZ should really care
about. We expose an interface IFeedGenerator, any class implementing which
implements the function getFeed which takes in an optional limit parameter to specify
the upper limit on the number of desired feed items. From XYZ's perspective, they can
simply invoke the FeedGeneratorFactory function, and call the getFeed() function on
the returned IFeedGenerator implementation. Internally, based on the FeedStrategy
function, we return a different class. We could as well have put all of the logic into a single
class (although not a good idea). How we implement this is completely up to us and is
hidden from XYZ.
[ 17 ]
Efficient Implementation of Basic Data Structures and Algorithms
The feed method returns an array of IFeed type, which is also an exposed interface.
Each IFeed consists of platformId to identify the social media platform the feed belongs
to, a string content, and string media, which is a URI pointing to the media used in the feed,
if any. The contents of IFeed can be discussed with XYZ and modified if needed.
All other members, such as the actual classes implementing the core logic of feed fetch, sort,
organize, most likely cache, and several other concepts which would need to be introduced
as the scale of this increases, are internal to us and totally abstracted from XYZ.
Now from XYZ's perspective, knowing this information, all they need to do is import our
module and use it in their application. One possible usage could be as illustrated in the
following code snippet:
import * as Feeder from "./vendor";
class FeedRenderer {
private recentFeedGenerator: Feeder.IFeedGenerator;
private popularFeedGenerator: Feeder.IFeedGenerator;
constructor(universalKey: string) {
this.recentFeedGenerator = Feeder.FeedGeneratorFactory
(Feeder.FeedStrategy.Recent, universalKey);
this.popularFeedGenerator = Feeder.FeedGeneratorFactory
(Feeder.FeedStrategy.Popular, universalKey);
}
There are several ways to import and export modules, which we will explore in the next
chapter. In the preceding example, we are explicitly including a reference to the vendor.ts
file which we looked at earlier.
[ 18 ]
Efficient Implementation of Basic Data Structures and Algorithms
With this setup, XYZ gets access to the exposed members of our Feeder module. They
simply call the FeedGeneratorFactory function to get access to
two IFeedGenerator types, such as one that fetches the most recent feeds, and one that
fetches the most popular feeds. From their standpoint, they don't really care whether it's the
same implementation or two different implementations under the wraps. All they care is, it
is of the type IFeedGenerator. The FeedRenderer class would be called into by XYZ's UI
elements to render the fetched feed.
The following diagram summarizes the factory pattern we've been discussing thus far:
[ 19 ]
Efficient Implementation of Basic Data Structures and Algorithms
Apart from the flexibility this offers to you as a vendor, in terms of internally managing the
concrete implementations, it also makes it easier for you to manage version updates and
rollbacks. Any new releases can be rolled out without breaking the consumer contract
(explicit consumer-driven contracts can be enforced too), and if anything were to break, you
can rollback to an earlier version, and the experience from the consumer's perspective
would be seamless.
This helps the consumer as well, in that if the preceding exposes API, becomes or is an
industry standard, and there are multiple such vendors available to choose from in the
market, the consumer can seamlessly switch between multiple vendors without having to
make major changes to their core code base.
As you can see, when leveraged wisely, classes and interfaces can have a high impact on the
longevity and scalability of your application, and consequently on it's performance.
// dummy method
const dummy = () => null;
// for...in
const forinLoop = () => {
let dummy: number;
for (let i in arr) {
dummy = arr[i];
}
}
// for...of
const forofLoop = () => {
let dummy: number;
[ 20 ]
Efficient Implementation of Basic Data Structures and Algorithms
// naive
const naiveLoop = () => {
let dummy: number;
for (let i = 0; i < arr.length; i++) {
dummy = arr[i];
}
}
In the preceding code snippet, we declare an array arr. We initialize it with 50,000 random
numbers. Then, we measure the time performance of three loops such as forof loop, forin
loop, and naive loop. Before we dig into the performance results, let's take a look at a side
note on the syntax.
We have declared the array using the generic array type, const arr:
Array<number> = [];. We can also declare it using the data-type-array
syntax, const arr: number [] = [];. Also, we've declared the
functions as constants, using the Lambda expressions. We could also write
them as old fashioned functions, function forinLoop() { ... }.
We are also passing functions as parameters, as
in, calculateTimeDifference(forofLoop). The function declaration
of this function is interesting, const calculateTimeDifference =
(func: () => void): number => { ... }. This basically says
that calculateTimeDifference is a function that takes a function which
takes zero arguments and returns void as an argument, and returns a
number.
[ 21 ]
Efficient Implementation of Basic Data Structures and Algorithms
interface Map {
[key: string]: string;
}
// for...in
const mapForIn = () => {
let dummy: string;
for (let key in map) {
[ 22 ]
Efficient Implementation of Basic Data Structures and Algorithms
dummy = key;
}
}
// for...of
const mapForOf = () => {
let dummy: string;
const keys = Object.keys(map);
for (let key of keys) {
dummy = key;
}
}
// naive
const mapForNaive = () => {
let dummy: string;
const keys = Object.keys(map);
for (let i = 0; i < 50000; i++) {
dummy = keys[i];
}
}
On Chrome, the forof loop outperformed the forin loop, but only slightly. On IE and
Edge, the forin loop recorded the best performance, while the naive loop remained the
least efficient across all browsers. Thus clearly, the forin loop is the recommended for
looping over objects such as dictionaries. Based on the use case, one should choose the
option that most makes sense.
[ 23 ]
Efficient Implementation of Basic Data Structures and Algorithms
Conditional statements are one of the most commonly used constructs in any language. In
TypeScript, you may implement a conditional using the if..else statement or
the switch…case statement. Let's take a look at these constructs.
The performance of the preceding code block would be the worst if decision is 100,
making 100 comparisons before our condition evaluates to true. If you notice,
this if..else chain is equivalent to a linear search, the time complexity of which in terms
of Big-Oh notation is O(n) where n is the total number of comparisons. In the worst case,
you would make n comparisons like in the preceding example. In the best case, the very
first comparison would evaluate to true. On average you would make n/2 comparisons. If
you have data points with the probability of different values that decision can take, you
can optimize the preceding if..else chain by making the higher probability comparisons
before the others. The time complexity of this optimized approach would still be O(n).
[ 24 ]
Efficient Implementation of Basic Data Structures and Algorithms
In order to improve the performance in a generic case, especially when the probabilities are
unknown, you can refactor the if..else chain to reflect binary search. In binary search,
you eliminate half of the choices at each stage, thereby yielding a logarithmic time
complexity O(lgn). Look at the following code snippet to get a better idea:
let decision: number = Math.floor(Math.random() * 100) + 1; //
random // number between 1 and 100
if (decision < 50) {
if (decision < 25) {
if (decision < 12) {
if (decision < 6) {
// all results < 6
if (decision < 3) {
// compare decision with 1 and 2
} else {
// compare decision with 3, 4 and 5
}
} else {
// all results >=6 and < 12
if (decision < 10) {
if (decision < 8) {
// compare decision with 6 and 7
} else {
// compare decision with 8 and 9
}
} else {
// compare decision with 10 and 11
}
}
} else { /* ... */ }
} else { /* ... */ }
} else { /* ... */ }
One thing that would strike you immediately with the preceding code snippet is that even
though it performs better than the linear checks, it's readability is a big pain. Code
maintenance is a big factor that would be impacted especially when working on large team
projects. It's a good time to look at the switch…case statement:
let decision: number = Math.floor(Math.random() * 100) + 1; //
random // number between 1 and 100
switch (decision) {
case 1: {
// do something
break;
}
case 2: {
// do something
[ 25 ]
Efficient Implementation of Basic Data Structures and Algorithms
break;
}
// ...
// ...
case 100: {
// do something
break;
}
default: {
// do something
}
}
On first look, the switch…case statement seems to be similar to the linear if..else
block. However, it is internally based on the browser you're running the script on, the
rendering engine would optimize the number of comparisons. Given this fact combined
with a much better code readability, you should choose the switch…case statement
whenever you can make single value comparisons.
For range comparisons, you would still need to use the if..else
statement, which can actually render optimal performance if implemented
efficiently.
// naive
const naiveSort = () => {
[ 26 ]
Efficient Implementation of Basic Data Structures and Algorithms
// optimized
const optimizedSort = () => {
let swapped: boolean = true;
while (swapped) {
for (let j = 0; j < arr.length - 1; j++) {
swapped = false;
if (arr[j] > arr[j + 1]) {
swapped = true;
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
In the preceding code snippet, we declare an array and initialize it with 50,000 elements,
each of which is a random number between 0 and 100,000. The sorting algorithm we're
looking at is bubble sort. Bubble sort works by bubbling the largest element to the end of the
array in each pass (assuming a non-decreasing sort).
[ 27 ]
Efficient Implementation of Basic Data Structures and Algorithms
The number of passes needed by this algorithm is one less than the number of elements.
Let's take a look at the following diagram to get a better idea:
[ 28 ]
Efficient Implementation of Basic Data Structures and Algorithms
As you can see in the preceding diagram, we start with a 6 element array. In Pass 1, we
make four comparisons starting from the first element, and performing a swap each time
we detect an order mismatch. For example, 87 > 12, which is a mismatch and hence we do a
swap. 87 > 45, so we swap again. 87 < 93, and so we do not swap. Finally 93 > 16 and 99 >
93, so we swap. At the end of Pass 1, we ensure that the largest element is at the end of the
array.
We perform four more such passes, ensuring that the largest element during that pass ends
up toward the end of the array.
Generalizing this for an n-element array, we can see that the total comparisons we will end
up making is (n-1)*(n-1), which when talking in terms of Big-Oh gives us a time
complexity of O(n2).
The preceding concept is implemented in the preceding code snippet under the
function naiveSort. While reading this, you may have already detected an inefficiency in
the preceding approach. We need not have (n-1) passes by rule of thumb. As you can see
at the end of Pass 4, we already have a sorted array and do not really need Pass 5. So, when
do we know when to stop? Answer: When there was no swap performed during a pass we
stop. This optimized approach is implemented in the preceding code snippet under the
function optimizedSort.
[ 29 ]
Efficient Implementation of Basic Data Structures and Algorithms
As you can see, a simple optimization has massive impacts on performance. On Chrome, it
outperforms the naive implementation by gigantic amounts. The optimized sort runs as fast
as a millisecond! And the naive sort takes almost 8 seconds! On IE and Edge, the findings
are even more dire. As expected, the optimized sort runs fairly quickly. However, the naive
sort never completes and the web page crashes even before the sort can complete!
Once again, the time performance despite having contrasting comparison is not the most
critical factor. CPU utilization and to some extent memory consumption are the resources most
severely impacted. Just to give you some context, the average CPU utilization for a web
page running advanced chat applications is only 0.5-3%. However, when the preceding
script is executed on a web page, the CPU utilization shoots up to 30-35%! This is one of the
reasons why the web page crashes. Note that the preceding percentage values are on a two
core processor with a maximum speed of 2.81 GHz.
There are several web/mobile applications that may perform the sorting of such a massive
scale. Consider a travel booking application for instance. Among the several thousand
options, different levels of sorting are performed, sorting based on prices, timings, and so
on. An optimal algorithm powering these sorts is of vital importance. Any inefficiency will
manifest itself as either UI spinners spinning forever, or application/web page
crashes. Either of these scenarios would take a massive hit on your application's user
engagement and ultimately on your business.
Operators
Let's now take a look at the several available operators you can leverage in TypeScript.
Quite a few have already been implicitly introduced to you via code snippets from previous
sections. Let's formally declare all the operators:
Arithmetic operators: The most obvious class of operators are the arithmetic
operators, which are used to perform arithmetic operations. The most obvious
arithmetic operators are addition (+), subtraction (-), multiplication (*),
division(/), increment (++), decrement (--), and modulus (%). The modulus
operator returns the result of what remains after a number is divided by another
as a whole. For example, take a look at the following code snippet:
As the usage of the remaining operators is natural, let's look at the next class of
operators.
[ 30 ]
Efficient Implementation of Basic Data Structures and Algorithms
The equals (==) operator exists in TypeScript in two flavors, strict mode
and lenient mode. The == is the lenient mode, while the === or triple
equals is the strict mode. With strict mode, the evaluation of the
expression to true is less than lenient mode, because in lenient mode there
is implicit type conversion whereas in strict mode there is no such
conversion. For example, 16 == '16' evaluates to true, whereas 16 ===
'16' evaluates to false.
if (this.instanceVariable) {
this.instanceVariable.DoOperation();
}
Bitwise operators: Apart from the preceding mentioned operators, there are
several bitwise operators, which perform advanced bit-level manipulations. Some
common bitwise operators are as follows:
Left shift (<<): Left shift shifts the bits in a number to the left, by the
specified number of bits, for example, (x << 2)
Right shift (>>): Right shift shifts the bits in a number to the right, by the
specified number of bits, for example, (x >> 2)
AND (&): The AND operator performs a bit-level AND on the bits of the
two specified operands, for example, (x & 4, which is x & 0...0100)
[ 31 ]
Efficient Implementation of Basic Data Structures and Algorithms
For the sake of completeness, lets also explore the typeof operator,
instanceof operator, and Compound Assignment Operators with the
help of the following code snippet:
// 1. compound assignments
let num: number = 40;
num *= 2; // num1 equals 80. this is same as num = num * 2
// 2. typeof
const str: String = 'test';
console.log(typeof num); // outputs number
console.log(typeof str === 'string'); // outputs true
// 3. instanceof
const arr: number[] = [1,2,3];
class ABC {};
const abc: ABC = new ABC();
[ 32 ]
Efficient Implementation of Basic Data Structures and Algorithms
typeof: The second operator in the preceding code snippet is the typeof
assignment. As can be seen, typeof num prints number and typeof str
prints string.
instanceof: The third operator in the preceding code snippet is the
instanceof operator. As can be seen in the preceding code snippet, this can
be used to query a given object to find which class it is an instance of. This
can be useful in determining the implementing class of an object passed to a
method that accepts an interface type as a parameter.
Summary
In this chapter, we looked at some basic data structures, constructs, and algorithms, and
explored the performance impact of leveraging these in an efficient manner. We understood
how these performance tweaks play a major role toward the durability, scalability,
maintainability, and the performance of your application.
After exploring these basic constructs, let's take a look at some declaration basics that
TypeScript offers in our next chapter.
[ 33 ]
Variable Declarations,
2
Namespaces, and Modules
In this chapter, we will take a look at the declaration basics exposed by TypeScript.
Declarations are a way to specify the existence of an entity to the compiler. Besides this and
more importantly, the correct use of the declaration constructs is key in writing readable
and scalable code.
Variable declarations
There are several different ways in which variables can be declared in TypeScript, such
as var, let, and const. There's a distinct difference between these, but the implications
that arise as a result of it are quite subtle. Instead of introducing the theory first, let's take a
look at some example declarations in the following code snippets and then deduce the
theory from it.
Exploring the Variety of Random
Documents with Different Content
+ − The Times [London] Lit Sup p426 Jl 1
’20 140w
Wis Lib Bul 16:237 D ’20 50w
20–10729
“The young people are simple and natural and the incidents are
never strained to produce dramatic effects, but those who have lived
in the country may feel that the absolute superiority of Marian and
her mother to all their neighbors is exaggerated.”
“While at times the author seeks to present his nation in the most
favorable light, as in the omission of any mention of the outrages
perpetrated by the revolutionary societies at the close of the
nineteenth century, his book is free from any attempt at propaganda.
Unfortunately, this cannot be said of the preface written by M.
Crabites.” D: Magie
“It is a concise and readable outline, giving not only the main
currents of political development but also some information
concerning economic and social organization.”
20–20995
With astonishing frankness Mrs Asquith tells the story of her life
and when she says in her preface that she has taken the
responsibility of the telling entirely upon herself, one can easily
believe her. Her dash and courage and unconventionality, her
affectionate nature and clever wit, her social position and close
association with events and people of prominence make the book
unusual. In her own words, she has related of her “manners, morals,
talents, defects, temptations and appearance” as faithfully as she
could. Her reminiscences are all of a personal nature without
reference to politics and public affairs. Both books are indexed and
illustrated.
Reviewed by H: W. Nevinson
Reviewed by E. L. Pearson
“Mrs Asquith has moved through great scenes; but the motion is a
flitting, rather than an act of spiritual observation, and therefore
when she sits down to recall her impression, it is apt to lack both
sharpness and refinement.”
“She is not well equipped for the panoramic display of the outer
world, and the remarkable fulness of her opportunity in that
direction is largely wasted. Mrs Asquith is no story-teller, it is not her
line; she lacks the seeing eye and the vivifying phrase. And yet she
elects to write a book that is all storytelling, all an attempt to
reproduce the brilliant phantasmagoria in which she has lived.”
+ − The Times [London] Lit Sup p716 N 4
’20 2200w
(Eng ed 20–8797)
20–4029
“Professor Athearn frankly states that the church cannot ask the
state to teach religion, but the church can teach religion at odd hours
during the week and on Sunday. The church can and must organize
and administrate a national system of religious education that will
parallel and correlate with the national secular system which is in
process of formation at the present time. He regards the Smith-
Towner bill as a large step in the direction of a unified, national,
secular system of education, and accepts it as a challenge to the
educational leadership of the church to produce a program which
will be equally scientific, equally democratic, and equally prophetic.
His discussion of national control, or direction, of a system of secular
and religious education is extremely worth while at this, the most
critical, time in the history of education in the United States.”
(School R) “Bibliography on educational organization and
administration.” (Booklist)
Reviewed by J. A. Artman
20–19448
“The book is full, racily written, and made alive with interesting
first-hand illustration.”
21–759
“Very simple and very real, told with sympathy, grace and a fine,
sure artistry, this picture of ‘Marie Claire’s workshop’ is a most
appealing book.”
+ N Y Times p20 N 21 ’20 640w
“In short, this is a special type of realism, and the cumulative effect
of it ... recalls as its nearest parallel, not prose but verse, Hood’s
‘Song of the shirt.’” Calvin Winter
“This is a book for gentle souls; although it is too deeply human for
the ingenuous.” A. G. H. Spiers
20–15345
“It is rich and poor, cold and hot, dull and deeply interesting. But
the impression of the whole is of something which has just not
succeeded.” K. M.
“The novel is one whose appeal will be to those who care for style
and thought rather than for plot and incident. It is a better book than
‘The Querrils.’”
“The scenes are described with the ability which ‘The Querrils’
showed Mr Aumonier to possess; but the book is less carefully
constructed, and the sense of incomplete finality which marred the
effect of the earlier novel in this one is more obtrusive. Mr Aumonier
studies situations rather than characters, and in contriving a
situation with a climax that is dramatic but not ‘stagey’ he has a
particular skill. At the same time, the book has a tendency to fall into
vaguely connected episodes, while the characters approximate too
closely to collections of impersonal attributes.”
20–9713
The action of the story takes place in the year after America’s
entrance into the war. Neith Schuyler, the heroine, has lived abroad
with an invalid father for a number of years, and following his death
has done relief work in France. She returns home hoping to learn to
understand America. To come nearer to the problem she leaves the
luxurious home of her two great aunts and takes a modest apartment
on Jayne street, just off Washington square. Here she comes into
contact with many shades of radical opinion and contrasts it with the
“capitalistic” attitude of her own family and friends. Two men fall in
love with Neith, Eustace Bittenhouse, an aviator, and Adam Frear, a
labor leader. She becomes engaged to Adam and then learns that
there has been another woman in his life, Rose Matlock, one of the
radical group. The attitude of the two women, who represent the new
feminism, puzzles Adam and he leaves for Russia. Eustace is killed in
France and Neith is left to grope her way into the future alone.
“Rather obscure and vague in some places, it will not have many
readers.”
“One should not chide Mrs Austin too much for her somewhat
blurred vision of the surface, since the greatness of her work lies in
the much rarer faculty, which she possesses, of being able to focus on
the inner significances.” J. C. L.
Our website is not just a platform for buying books, but a bridge
connecting readers to the timeless values of culture and wisdom. With
an elegant, user-friendly interface and an intelligent search system,
we are committed to providing a quick and convenient shopping
experience. Additionally, our special promotions and home delivery
services ensure that you save time and fully enjoy the joy of reading.
ebooknice.com