Bytes #54 - 1.1 billion Taco Bell Cheesy Bean & Rice Burritos

1.1 billion Taco Bell Cheesy Bean & Rice Burritos

Issue #54.June 28, 2021.2 Minute read.

Deno's eating Fresh, the new Spec goes live, and we found the most cursed bento box on the internet. Welcome to #54.


Deno Stompers

Get a new web framework with every five-dollar footlong

Deno -- So fresh and so ~~clean~~ fast

As if we weren't writing enough JSX already, the folks at Deno have teamed up with Subway to create a new Preact-based web framework called Fresh.

Quick Review: A few months ago we told you about Deno Deploy, the new hosting service made by Deno (the company) which runs on Deno (the JavaScript runtime). They just announced Beta 1, and the headline feature is speed.

"We believe Deno Deploy is the fastest serverless system available." -- Ryan "Tell-us-how-you-really-feel" Dahl

Fresh was announced alongside the Deno Deploy beta as the official, Deno-blessed web framework (#BlessedBeTheFruit). So, how does it stack up against other web frameworks?

  • It has file-system routing, just like Next.js

  • It's built for server-rendering on the edge -- meaning it's slim and fast

  • It has no build step -- since Deno speaks JSX and TypeScript, you deploy your code to Deno Deploy and it just works

  • It uses a novel useData hook for orchestrating fetching data on the server

  • While intended to be used on Deno Deploy, it'll work just fine on any Deno server

Otherwise, it has all the same features and hooks as Preact, so it should feel pretty familiar. Plus, you'll get access to the ever-growing repo of Deno modules.

Along with Fresh, Deno also announced its new take on the Express HTTP framework by releasing oak (an HTTP middleware library) and sift (an HTTP routing library).

The Bottom Line

We're really excited to see this Subway partnership expand. Maybe Deno will start using their VC bucks to give away free subs with every deployment? (Just watch out for the bread... and the tuna.)

Deno -- Eat Fresh!


Unlayer

Safety from the storm [sponsored]

Unlayer's Embed Plugin wants to change your life

Trust me on this one -- building responsive email templates that *actually* work on every email client is a pain that I wouldn't wish on any of you (unless you're reading this email on Outlook right now).

But thanks to Unlayer's new Embed Plugin, no one has to feel that pain ever again 🙏.

Unlayer is a simple JavaScript SDK that lets you add a white label, drag-and-drop editor to your SaaS app in 5 minutes, instead of spending hundreds of engineering hours building it yourself. They've also got specific components for React, Angular, and Vue so you can seamlessly integrate it with the rest of your app.

So check out Unlayer's free trial, and start making it easier for your SaaS customers to create high-quality, fully-responsive email templates and landing pages that work on every email client and every browser (yes, even IE and Outlook). They'll love you for it forever.


One Question Interview

What will building for the web look like in 5 years?

"I think that over the next few years, as new developers advance into tech leadership roles, we're going to see changes in what dev teams prioritize. From a technical standpoint, that might mean developing new and innovative ways of ensuring web accessibility, or expanding no code development solutions to improve dev experiences. As far as what will we value most in five years? I guess that remains to be seen. That's why it's important that we prepare our systems to be as nimble and adaptable as possible."

Tracy Lee Tracy Lee is the CEO of This Dot Labs, an RxJS Core Team member, and Google Developer Expert. She'll be giving a talk this Thursday entitled, "From beginner to expert in web performance" for ui.dev subscribers.

Job Post

2x Sr. Frontend Engineers - React | 100% Remote

Close.com is looking for two experienced individuals that have a solid understanding of React and want to help design, implement and launch major user-facing features. They are a 100% globally distributed team of ~45 high-performing, happy people that are dedicated to building a product our customers love.


Cool Bits

  1. Emily and Phil wrote a fantastic article about how Not All Components Are Created Equal -- which reminded me of how not all bento boxes are created equal either.

  2. Daniel wanted to learn more about Bitcoin, so he built it in JavaScript and live coded it during a conference talk. For his next trick, he'll team up with a TikTok star to create a sh*tcoin, pump it to the moon, cash out, and disappear to the Cayman Islands.

  3. Juke Build is an AKE-less build system for JavaScript and Node.js that's simple to use, strongly typed, and still in progress. TBH I don't know what AKE-less means and at this point I'm too afraid to ask.

  4. Vercel just raised $102m at a $1.1b valuation 🦄. This brings up the question I'm surprised no one is asking. Would you rather have 1 Vercel, or 1.1 billion Taco Bell CHEESY BEAN AND RICE BURRITOS? You know what we're choosing 🌯.

  5. Josh Comeau wrote a great article on Demystifying styled-components. Now we just need him to write another post that demystifies whatever the hell this cursed Netflix show is. Because I'm still quite mystified, tbh.

  6. Gabriele wrote an in-depth article on the different approaches you can take to Parsing in JavaScript, which you should probably memorize before your next job interview in order to prove that you know your stuff when it comes to tasks that you'll rarely need to complete.

  7. Tanner created iPod.js -- a fun web app that connects your Spotify account to a classic iPod UI and lets you play that addicting Brick Breaker game. So plug in some crappy headphones, blast some mid 2000's Taking Back Sunday, and pretend like you just got done dominating your friends on the Guardian map in Halo 3.

  8. Andrew Clark from the React team gave a quick preview on Twitter of what it'll be like when React releases everything they've been working on the last few years.


Megan Thee Stallion

Get ready for Hot Spec Summer™

ES2021 - The Song of the Summer

Coming ~~soon~~ now to an Spec near you -- ECMAScript 2021 / ES12 / Nü-Script (ok fine, we made that up). Whatever you want to call it, the newest version of JavaScript is finally here -- complete with five shiny new TC39 proposals that have been freshly added to the Spec.

Since we take our responsibility of keeping you up to date on the JavaScript ecosystem very seriously, here's everything you'd ever want to know about ES2021.

Logical Assignment Operators

You already know about the assignment operator. It lets you put values into variables.

let postAuthor = 'Tyler'
postAuthor = 'Alex'

You also likely know about logical operators, which return either true or false based on some logical operation. They include the AND operator (&&), the OR operator (||), and the recently added nullish coalescing operator (??).

Finally, you know about the mathematical assignment operators. These let you perform a mathematical operation on a variable with the value you are assigning, such as currentNum += 5 which adds 5 to the value of currentNum.

TC39 decided it was time to introduce these operators to each other and created Logical Assignment Operators, which do some logic on the value in the variable when deciding whether to assign a value to it. We'll look at each logical assignment operator individually.

&&=

You can pronounce this as "And And Equals". When you use this, it only assigns a new value to the variable if the variable's current value is truthy — the truthiness of the new value doesn't matter. These two statements are roughly equivalent.

// Without Logical Operators
a && (a = b)
// With Logical Operators
a &&= b

To demonstrate this, lets create an object called "favorites" and try adding some lists of favorites to it.

let favorites = {}

// Without first creating the property,
// this won't add the property to the object
favorites.favoriteNumbers &&= [5]
console.log(favorites) // {}

// We'll add an empty array
favorites.favoriteNumbers = []

// Now when we assign to this property,
// the assignment will work, since it already exists
favorites.favoriteNumbers &&= [15]
console.log(favorites) //{favoriteNumbers: [15]}

In this case, if the property doesn't exist, it doesn't create the property. But if it already exists, it overwrites it with the value we provide.

||=

You can call this one "Or Or Equals". It works similarly to &&=, except instead of checking to see if the existing value is truthy, it only assigns the new value if the existing value is falsy.

// Without Logical Operators
a || (a = b)
// With Logical Operators
a ||= b

Once again, we'll add a property to a "favorites" object to demonstrate it's behavior.

let favorites = {}

// Without first creating the property,
// this will assign it. Useful for initializing the array.
favorites.favoriteColors ||= []
console.log(favorites) // {favoriteColors: []}

// Now that the property has been initialized,
// we can't change it with ||=
favorites.favoriteColors ||= ['red']
console.log(favorites) // {favoriteColors: []}

??=

This one is pronounced QQ Equals, and it is exactly the same as ||= except it checks if the existing value is nullish, meaning either null or undefined. If it is, it will assign the new value. These two statements work the same.

// Without Logical Operators
a ?? (a = b)
// With Logical Operators
a ??= b

We'll take one more look at how we can use this with a "favorites" object.

let favorites = {}

// Since properties are undefined before initialized,
// we can use ??= to set an initial, or default, value
favorites.favoriteColorCount ??= 0
console.log(favorites) // {favoriteColorCount: 0}

// Once we've initialized the property,
// we can't change it with ??=, even if it's 0
favorites.favoriteColorCount ??= 10
console.log(favorites) // {favoriteColorCount: 0}

// If we reset the value by setting it to null
// we can set it with ??= again
favorites.favoriteColorCount = null
favorites.favoriteColorCount ??= 10
console.log(favorites) // {favoriteColorCount: 10}

Notice that it doesn't assign the property when it's value is 0, because that value isn't nullish.


Why would you use this? These operators can save you a little bit of effort as you are assigning values to other values or object properties based on the value you are replacing. ||= and ??= can be especially helpful for initializing values without accidentally overriding them later.

Numeric Separators

Until now, numbers in JavaScript had to be written as a series of digits, without any kind of separator digits allowed. This works fine for small numbers, but once you get to the millions place, it can be hard to tell what number is what. With ES2021, you can now add underscore separators anywhere in the number, ahead or behind the decimal point. This lets it work with different separation formats from different parts of the world.

const normalNum = 123456.78912
const separatedNum = 123_456.78_9_12

console.log(normalNum === separatedNum) // true

// Use a separator to differentiate between dollars and cents
const moneyInCents = 349_99

Why would you use this? Because you want to be able to read numbers that have more than three digits without squinting at your screen and using your cursor to count the digits. Numeric Separators have no performance impact — they works exactly the same as regular numbers, but they're a lot easier to read 🎉.

String.prototype.replaceAll()

The String.prototype.replace() method only replaces the first occurrence of a string when you use a string as the input. Before ES2021, replacing all of the occurrences of one string in another required using a regular expression with the /g flag on the end.

const originalString = 'Always give up! Always surrender!'

const replacedString = originalString.replace('Always', 'Never')
console.log(replacedString) // "Never give up! Always surrender!"

// You must use the "g" global flag
const regexReplaceString = originalString.replace(/Always/g)
console.log(regexReplaceString) // "Never give up! Never surrender!"

While this works just fine, it is also a little counter-intuitive — I always expect that every string will be replaced without me needing to use a regular expression. Plus, the regular expression makes it a little harder to read.

ES2021 adds the String.prototype.replaceAll() method as a convenience to let you pass a string as the input.

const originalString = 'Always give up! Always surrender!'

const allReplacedString = originalString.replaceAll('Always', 'Never')
console.log(allReplacedString) // "Never give up! Never surrender!"

This method still works with regular expressions, however it requires that they use the global /g flag — otherwise it will throw an error. There are also special strings you can use inside your replacement string, such as $& which represents the matched string. I can use this to easily wrap the existing string with other strings, like adding quotes to the matched string.

const originalString = 'Always give up! Always surrender!'

const allReplacedString = originalString.replaceAll('Always', '"$&"')
console.log(allReplacedString) // '"Always" give up! "Always" surrender!`

Why would you use this? String.prototype.replaceAll() makes replacing every instance of a string in some text just a little bit easier, all without needing messy regular expressions.

Promise.any()

Whenever we we need to do something asynchronous in JavaScript, we reach for the trusty Promise. These let us schedule work and provide a way to resume executing our code once the work is done. JavaScript Promises can be in one of three states — "pending", "fulfilled", or "rejected". We'll say that "fulfilled" and "rejected" are resolved states, meaning the promise is done processing.

There are a few ways to orchestrate Promises in JavaScript. Promise.all() runs an array of promises and runs them concurrently, resolving once all of the promises fulfill or rejecting when any one of them reject.

import getBlogPost from './utils/getBlogPost'

Promise.all([getBlogPost(1), getBlogPost(3), getBlogPost(4)])
  .then((blogPosts) => {
    // Do something with our array of blog posts
  })
  .catch((error) => {
    // If any of the promises rejected, the entire Promise.all call will reject
  })

Promise.race() also takes an array of promises, but it fulfills or rejects as soon as any one of the promises fulfills or rejects.

import getBlogPost from './utils/getBlogPost'
const wait = (time) => new Promise((resolve) => setTimeout(resolve, time))

Promise.race([
  getBlogPost(1),
  wait(1000).then(() => Promise.reject('Request timed out')),
])
  .then(([blogPost]) => {
    // If getBlogPost fulfilled first, we'll get it here
  })
  .catch((error) => {
    // If the request timed out, the `Promise.reject` call
    // above will cause this catch block to execute
  })

Just last year we were introduced to Promise.allSettled, which runs all of the promises, regardless of whether any of them fulfill or reject. Once all of them are resolved one way or the other, it returns an array describing the results of each promise.

import updateBlogPost from "./utils/updateBlogPost";

Promise.allSettled([
  updateBlogPost(1, {tags:["react","javascript"]})
  updateBlogPost(3, {tags:["react","javascript"]})
  updateBlogPost(7, {tags:["react","javascript"]})
]).then(results => {
  // Regardless of whether any of the promises reject, all of them
  // will be executed.
  console.log(results);
  // [
  //   {status: "fulfilled", value: {/* ... */}},
  //   {status: "fulfilled", value: {/* ... */}},
  //   {status: "rejected",  reason: Error: 429 Too Many Requests}
  // ]
})

Promise.any() is a new Promise function that works a bit like Promise.race(). You pass it a list of promises. It will resolve as soon as one of the promises is fulfilled, but it won't reject until it's done resolving all of the promises. If every single promise in the list rejects, it returns what's called an Aggregate Error, which groups together all of the errors from the promise rejections.

In this example, we'll do a little bit of web scraping to see which website loads the fastest. We want it to ignore any sites that might be offline too. If you try running this in a browser, you'll get an AggregateError, due to CORS security errors. However, if you run it in NodeJS v16+ with a fetch polyfill, like node-fetch, you'll get a response from one of the sites.

Promise.any([
  fetch('https://google.com/').then(() => 'google'),
  fetch('https://apple.com').then(() => 'apple'),
  fetch('https://microsoft.com').then(() => 'microsoft'),
])
  .then((first) => {
    // Any of the promises was fulfilled.
    console.log(first)
  })
  .catch((error) => {
    // All of the promises were rejected.
    console.log(error)
  })

Why would you use this? Promise.any() lets you run a list of promises concurrently, ignoring any that reject unless all of the promises reject.

WeakRef and FinalizationRegistry

JavaScript famously uses a garbage collector to manage memory. That means you don't have to de-allocate variables when you are done working with them, which is incredibly convenient. However, it does mean that if you're not careful, variables can hang out in memory for too long, causing memory leaks.

The job of the garbage collector is to keep track of the references that objects have to other objects – like global variables, variables defined in a function closure, or properties on an object. Any time you assign an existing object to another variable, another reference is created and the garbage collector takes note. These types of references are called "Strong" references. The memory for those objects will be retained until there are no more references to the object. At that point the garbage collector will remove the object and clean up the memory.

Sometimes, though, you might want to have an object be garbage collected even sooner. For example, we might want to have a cache that we want to have the garbage collector clear out more frequently, just in case that cache fills up with big objects that consume all of the browser's memory. For that, we use a WeakRef.

We can create a WeakRef with its constructor, which takes an object of some kind.

// This is a regular Object
const blogPostCache = {}

// This is a WeakRef Object.
const weakBlogPostCache = new WeakRef({})

To access values on our weakBlogPostCache, we need to use the .deref method. This lets us access the underlying object, which we can then mutate.

const blogPostRecord = {
  title: 'A really long blog post',
  body: 'This blog post takes up lots of space in memory...',
}
// We'll use spread syntax to clone this object to make a new one
blogPostCache['a-really-long-blog-post'] = { ...blogPostRecord }
weakBlogPostCache.deref()['a-really-long-blog-post'] = { ...blogPostRecord }

console.log(weakBlogPostCache.deref()) // {"a-really-long-blog-post": {title: ..., body: ...}}

At this point, there's no telling when weakBlogPostCache will be garbage collected. Each browser engine has a different schedule for running the garbage collector. Usually it will run automatically every couple of minutes, or if the amount of available memory starts getting low. If you are using Google Chrome, you can click the College Garbage icon in the Performance dev tools tab.

Once the WeakRef is garbage collected, calling .deref will return undefined. It's up to you, the developer, to handle those situations, perhaps by creating a new empty WeakRef and populating it with fresh content.

FinalizationRegistry

It's possible that checking to see whether weakBlogPostCache.deref() is undefined isn't responsive enough. If we wanted to reinitialize our empty cache the moment it was garbage collected, we would need some kind of callback from the garbage collector.

The FinalizationRegistry constructor was released alongside WeakRef to register callbacks to be called when a WeakRef is garbage collected. We can create a registry, pass it a callback, and then register our WeakRef with that registry.

Since the WeakRef's contents are gone when our callback is called, we need to pass some other value to the registry to help us know which WeakRef was garbage collected. When we register our WeakRef, we register a proxy value that is passed to the callback function. In the example below, that value is "Weak Blog Post Cache".

let weakBlogPostCache = new WeakRef({})
const registry = new FinalizationRegistry((value) => {
  console.log('Value has been garbage collected:', value)
  // Reinitialize our cache
  weakBlogPostCache = new WeakRef({})
})
registry.register(weakRefObject, 'Weak Blog Post Cache')

In the above example, once our weakBlogPostCache is garbage collected, the FinalizationRegistry will log Value has been garbage collected: Weak Blog Post Cache.

This feature is by far the most complicated of all of the features introduced; it's intended only for the most low-level use-cases, so you likely won't be messing with it unless you are writing libraries in JavaScript or applications with complicated memory requirements. Regardless, it opens up some performance optimizations that wouldn't be possible before. If you want a more in-depth explanation, including a few notes of caution, check out the full TC39 proposal.

Why would you use this? If you need to keep a cache of large objects without running out of memory, WeakRef can make the garbage collector remove those objects a little bit sooner. If you need to know exactly when one of your WeakRef objects has been removed from memory, you can use FinalizationRegistry

Join Bytes

Delivered to 105,434 developers every Monday