Episode 78 - October 18, 2021

setTimeout(newEpisode)

00:00 / 00:00

This episode is sponsored by...

Shownotes

This week, The Enjoy the Vue panel digs into the topic of asynchronous event loops: how it can save you time, but also how it can trip you up. Asynchronous update queues are an efficient way for platforms like Vue to save time and energy by recognizing a group of similar commands and doing a batch run at the same point in time. We get into event loops, how the term ‘next tick’ came about, and how synchronous stacking can cause a Stack Overflow Error. You’ll also hear some of our favorite terminal commands, including a special tidbit on how to say ‘please’ to your computer! Lastly, we share our picks of the week that will add joy, intrigue, and deliciousness to your life, so make sure you tune in to hear it all!

Key Points From This Episode:

  • Introducing today’s topic: asynchronous event loop in JavaScript.
  • An asynchronous update queue and why Vue uses one.
  • Why an asynchronous update queue is so efficient.
  • How an asynchronous update queue can also sometimes cause problems.
  • Where the term ‘next tick’ originated and how it is applied today.
  • A breakdown of event loops and stack heaps.
  • Tessa shares her understanding of blocking.
  • Why a blocking operation is synchronous.
  • Alex explains what the heap is and how items transition to the stack.
  • Recursive functions and the stack overflow error message.
  • The team shares their favorite terminal commands.
  • Hear our picks for the week, which include gourmet sour gummies, intriguing portraits, and a fascinating new board game! 

Tweetables:

“When you make a change to your data in Vue, it doesn't happen right away because that would potentially be inefficient. What it does is it groups all the changes together and then batch runs through them at a set point in time. That's the queue that they all get added to.” — @EnjoyTheVueCast [0:02:04]

“Basically, it's like doing your math without showing the work. That's what Vue does. Teachers love it.” — @EnjoytheVueCast [0:03:20?]

“My understanding is that blocking doesn't mean it never happens. It's just like I'm going to save all of these user interactions until the next time that the queue is free. Then, I'm going to jam all of them in there. You're going to get all 500 clicks in one second.” — @EnjoytheVueCast [0:18:25]

“There is this nebulous event that may or may not happen. When it happens, that click, that event doesn't necessarily fire immediately. It gets put on the end of the event queue, the event loop queue.” — @EnjoytheVueCast [0:19:16]

Transcript

[EPISODE]

[00:00:10] ANNOUNCER: This episode is brought to you by Cloudflare Pages. For more, visit enjoythevue.io/cloudflare-pages.

[00:00:21] AR: Knock, knock.

[00:00:22] AC: Who's there?

[00:00:23] AR: Async.

[00:00:24] AC: Async, who?

[00:00:25] AR: Hello, and welcome to Enjoy the Vue. I'm Alex. Today, on our panel, we have Ari.

[00:00:32] AC: Hello.

[00:00:34] AR: And Tessa. Hello. Today, we'll be talking about the asynchronous event loop in JavaScript, and to a certain extent, Vue. Have either of you all really used async/await very much? Asynchronous programming, lots of stuff asynchronously, then much of that?

[00:00:56] AC: More of a promises girl, but yeah, I've used async/await as well. Have some horror stories.

[00:01:04] AR: War stories.

[00:01:05] T: Yeah, I love async/await.

[00:01:07] AR: I have definitely used it, and I really did not understand what the heck was going on when I was first using it when I got into programming. There are times that I wish somebody had explained it to me a little bit better earlier.

[00:01:23] T: I don't think async/await was around when you got into programming.

[00:01:26] AR: It was in a proposal when I got back into programming. Even then, at that point, we had callbacks. That mental model did not work for me at all.

[00:01:39] AC: Insert callback to that episode, where we made callback jokes.

[00:01:45] AR: Today, we want to talk about the event loop and asynchronous programming. Vue has its own asynchronous update queue that it uses. Tessa, what is an asynchronous update queue?

[00:02:01] T: Basically, the idea is that when you make a change to your data in Vue it doesn't happen right away, because that would potentially be inefficient. What it does is it groups all the changes together, and then batch runs through them at a set point in time. That's the queue that they all get added to. One of the advantages of this is, let's say that I have a shopping cart. I really want to add a specific Legend of Zelda game to my shopping cart. For some reason, I'm very passionate about this specific game. Boldly, largely passionate.

I'll add the game, and then I'll change the amounts on the game, the quantity of the game on my card a bunch of times. I'll make it five, and I'll make a two and they'll make a one, I'll make it five. Let's say, I do it programmatically. Vue could update the data to be two and then five, and then whatever all the other numbers I said were. Or it could see that I'm changing the same thing over and over and over again, and be like, “Okay, I'm just going to take the last number. I'm not going to go through all that unnecessary additional work.” Basically, it's like doing your math without showing the work. That's what Vue does. Teachers love it.

[00:03:24] AC: In most cases, that's a good thing. Every once in a while, it's not.

[00:03:32] T: Yeah, because it all happens at this special point in time, known as the next tick. If you're expecting things to show up, and you're messing around with things in a way that the next tick isn't going to trigger yet, then you can run into frustrations where you’re like, “Hey, my UI isn't updating,” because it's still waiting on the next tick to update.

[00:03:54] AC: One example I have of when that didn't work out well for me was, I was trying to control multiple uploads from a single parent, but I didn't want the uploads to start until the user clicked a start button. They could select the files. Then once they'd selected all the files they wanted, then they could hit start. Then I needed a way to tell the children that it was time to start the upload.

I was like, “Okay, I'll just have a property that is start upload, and I'll set it to true when it's ready. In case they want to add more, I need to then set it to false again after.” I programmatically set it to true and then false, but nothing happened, because they only knew about the final value of false. That's where fun set timeouts come in. Or, if you want to feel fancy, next tick.

[00:04:52] AR: I actually ran into that. Just ran into that just the other day, where –

[00:04:57] T: Yeah. I was going to say, you're using web components, so how did you run into it?

[00:05:01] AR: Well, okay. I was making a new command for my Twitch stream to show confetti all over the screen when somebody types in the right command. It's using a canvas element, and so I'm programmatically adding some settings to an array. Then I needed to use the canvas element generated by adding things to that array. Because the thing was not actually in the array yet, I had just told it, “Hey, go put it in the array.” The element hadn't appeared yet, because it hadn't rendered, so I had to be like, “Okay. Wait. Hold on. Wait until the data has actually updated the DOM. Then we can start applying effects to it and stuff.” Then, there were set timeouts involved with that as well. It was fun.

[00:05:48] T: All this happens at the point of the next tick, but what is the tick, I think is, is the pretty big question? I don't know where this metaphor came from. I'm not a big fan of it, because my understanding is a tick is basically one entire cycle of an event loop. What comprises an entire cycle is basically, every time a task gets done, which is a certain type of operation, and then there are smaller types of tasks, like micro tasks, that defines the length of the event loop.

It's one big task, and then a bunch of little tasks. Next time you have another big task, then that would be the next loop. If you think about a clock, when it ticks one, that's not a whole cycle of a clock, so I don't really know why it's called the tick, and this is the next tick. I think, it's something that comes from more lower level programming languages.

All this stuff in your next tick happens at the end of the loop. The Vue implementation, specifically, at least, if I'm remembering correctly, as of 2017, or 2018, is that it wraps all of your little micro-task things, usually things that you might put in a promise, stuff like that, into a set immediate, and then it'll run that set immediate at the end of the loop in that next tick moment. Then it'll run all the other internal Vue stuff around that time as well.

It's weird, because if you use set immediate, but set immediate is not available, then it will default to a set timeout with a timeout of zero. I don't remember the details of this. I was testing it out for the talk that I gave at VueConf in 2018. I tried set immediate and set timeout, and I think, set immediate ran after set timeout with a timeout of zero. According to the implementation, it should either run before set timeout, if it is actually set immediate. Or, it should run in order, whether it's set timeout or set immediate, if they're all going to be set timeouts anyway, but it didn't do that.

[00:08:00] AC: I think it was 2019.

[00:08:03] T: Ooh. Good memory. Wait.

[00:08:05] AC: Either way, we'll find a link to the talk in the show notes.

[00:08:09] T: It was 2018. Because 2019 VueConf was the last – No, that was 2020 VueConf was last, and I want to say. You’re right.

[00:08:16] AC: It was literally a week before the world shut down.

[00:08:20] T: Actually, Austin shut down the day I was flying out. Yeah. I mean, that's nitty-gritty stuff that you probably – I would be very surprised if you needed to know to that level of detail to get your app working. It can be hard to wrap your mind around, if you're not as familiar with asynchronous programming/have not encountered the event loop before, or the Phil Roberts talk about the event loop.

[00:08:48] AC: Yeah. For example, I don't know if you guys have ever done this. You tried to do something with a ref in a component and the mounted hook, and it didn't work, because it didn't exist yet. Oh, literally.

[00:09:06] T: Yeah. Or trying to use the referee actively, which wasn't a thing at that point in time.

[00:09:11] AR: There was one job I did, where we had to integrate jQuery stuff into a Vue install. There was a lot of next tick, where it was like, okay, I need to wait and make sure that the element is there, so that the jQuery stuff will work correctly.

[00:09:29] AC: Okay. I have, why? Why?

[00:09:32] AR: That job was, there was a two –

[00:09:33] T: Ari, I’ve worked on two apps with jQuery and Vue.

[00:09:37] AR: Yeah. There was a theme that was written in Bootstrap 3, which heavily uses jQuery, as well as some things where it was like, a carousel and stuff. I was like, I am the only developer on this. I don't have time to re-implement a carousel. I will make this work, and so I did. I got very good at being like, “All right, where am I in the lifecycle?” We're here. Then, it's going to do this thing, and so I need to wait until this. Then I'm going to do a next tick and then wait for another next tick, and then it will do the thing and it'll be great.

[00:10:06] AC: I'm a big fan of just using recursion and mounted, until that’s enabled. I wish that we’re joking. It’s not.

[00:10:18] T: We weren't using bootstrap. I think, we just used jQuery, because somebody liked it. Yeah, it was a brand-new greenfield view app with jQuery. Eventually, they did take it out, but they were very sad. That was after six months of development.

[00:10:32] AC: Why?

[00:10:33] T: Sometimes, you just got to access stuff on the DOM, Ari. How else are you going to do it?

[00:10:38] AC: I don't know. Vanilla?

[00:10:41] T: Ew.

[00:10:43] AR: You need that you need that IE9 support.

[00:10:45] T: Something, something hot take. This is why I learned Vue, so I don't have to learn JavaScript. Just kidding.

[00:10:49] AC: I did recently have to refresh my memory on how to do things the vanilla way recently. Every once in a while, Vue doesn't have a way to do what you need to do.

[00:11:02] AR: Shock.

[00:11:03] AC: Yeah. No, I needed to set the background color of a checkbox based on what ID it was associated with. Easiest way to do that was just vanilla, JavaScript accessing the DOM. I had to do it in a ref and mount it to check if that checkbox was already checked when it's loaded. That was super fun. Really, I just touched on all the things we just talked about.

It's very pretty, because yeah, the thing was, it's an interactive table and set of graphs, and you can select which graph plots you want to see from the table. Given the screen real estate constraints, like we couldn't show a full legend in the graph. We're like, “Well, what if we made the color of the checkboxes the same color as the plots for that organization?” That's what we did. Not super accessible, but oops. You can zoom in on the graph, and it shows you the full legend, FYI.

[00:12:12] T: Yeah. I think, sometimes working with the update queue can be tricky. My own investigation into this stuff started when I had to update some unit tests. There was six next ticks in there in a row. There's set timeout next tick, next tick, set timeout. I was like, “Why do we need all these next ticks?” They were like, “I don't know. Without that number of next ticks, it just doesn't work.” I was like, “Well, that doesn't make sense.” I was like, “What the heck's a next tick?”

At the time, it just said like, when updates to the DOM happen, which is my understanding, this is actually the virtual DOM and not your actual DOM. The actual DOM changes happen at a later point in time, but you can get you. Usually, it's hard to get between the next tick where it changes the data, and then the DOM update. You'd have to be doing something really on purpose to get to that area in the loop, I think.

Let me add another segue to the event loop, and let's see if we can get there this time. It's tricky. It's helpful to have an understanding of the event loop, or other loop processes to understand what's going on, but it can still be a little bit confusing, because it is asynchronous.

[SPONSOR MESSAGE]

[00:13:24] ANNOUNCER: Previously on Cloudflare for the Dramatic.

[00:13:27] ACTOR 1: Hey, I need a website for my rain forest themed bookstore, but I don't have a big budget for ongoing server fees. Is that like something you can do?

[00:13:36] ANNOUNCER: Now, Cloudflare for the Dramatic!

[00:13:42] ACTOR 2: Did you see the requirements list for this site?

[00:13:46] ACTOR 3:  I know. It's a 1,000 meters long.

[00:13:49] ACTOR 2: They need us to use a JavaScript framework.

[00:13:55] AC: Cool. Cloudflare Pages supports jams.

[00:13:57] ACTOR 3: And they need something called Git integration?

[00:14:01] AC: Yeah. Cloudflare Pages allows you to publish right from your GitHub repos.

[00:14:04] ACTOR 2: On top of all of that, they expect this beast of a website to be performant? Ha!

[00:14:13] AC: Ehem. Like I've been trying to say, Cloudflare Pages supports all that, and allows you to collaborate with others using advanced site previews with unlimited admin seats, so you can include the whole team. Plus, it's super performant, thanks to their vast edge network. To learn more visit, enjoythevue.io/cloudflare-pages.

[Inaudible 00:14:43]

[00:14:46] ACTOR 3: Oh, no. That was the client.

[00:14:49] ACTOR 2: What?

[00:14:50] ACTOR 3: They said the site needs to call it Top Secret Secure Bookstore API. Aah.

[00:14:58] ANNOUNCER: Oh, no. What will happen now? Will the team be able to figure this out? Will they get that jam stack website up and running? Will they be able to make a site that works smoothly across the globe? Find out next time on Cloudflare for the Dramatic!

[00:15:14] AC: I guess, I’ll add this to the next sprint.

[EPISODE CONTINUED]

[00:15:19] T: We all know what the event loop is, right?

[00:15:22] AR: Isn't that the conference circuit that we go on to give talks on the event loop?

[00:15:26] T: Oh, you're alive.

[00:15:27] AR: Sorry, I was looking at the Vue 3 source code, trying to figure out next tick. I didn't. Good job me.

[00:15:33] T: Always, always use Siri, get your monitor and smiling. Somebody asked me to guess what you’re doing. It would not have been looking at Vue 3 source code. Now I know.

[00:15:43] AR: It just makes me so happy. No, the event loop is the thing where you can delay stuff and then do it later, the things, and it's a synchronous. Yeah.

[00:15:56] AC: It’s looking about a stack, a stack heap. I don't know.

[00:15:59] AR: There's a whole heap of stacks in there.

[00:16:02] AC: Queue.

[00:16:07] T: I'm just looking at that graphic that you found on MDN, Ari. I’m thinking like, you know, those objects look like meatballs, if I'm squinting. It's basically like, you're giving a bunch of JavaScript commands. It's like, how does it determine what order all of those things are going to execute in? In my experience, not uncommon to get as a question on a job interview. I haven't thought about the loop in a while, so my understanding is a little a little rusty and not in the backend sense.

It's also what determines your call stack. When you're trying to debug something, and you're looking at all the stack frames, or execution context in the console, that's a result of the queue. It's like, I want to do a bunch of stuff and I'll be like, “Okay, we need to put a bunch of stuff, so we'll add that to the stack, and that's one stack frame.” Then you're like, inside that you're “Oh, I need to do more stuff.” Let's say you're doing a loop inside a loop. It's like, okay, well, that's another context, so it adds another stack frame.

The way I'm describing is very confusing. Basically, it's like a multiple data structures that control JavaScript, because something about JavaScript being single threaded, but we all need more than one thing to happen at a time. Making external calls to now, I can't think of the word, but things outside of JavaScript, like the C runtime, or something to do extra tasks for you. That's all handled by this event loop system.

[00:17:37] AR: Since JavaScript is single-threaded, and ties into how the system renders the web page. If your task is taking too long, it will block human interaction. If your tab ever gets the spinning wheel of death, it's usually what it is, is that you've done something that's blocking the thread that's rendering and handling input and stuff, and you didn't made a booboo.

[00:18:07] AC: That's why we have asynchronous programming in JavaScript.

[00:18:10] AR: Yes.

[00:18:12] T: Yay.

[00:18:13] AR: Yay.

[00:18:14] AC: The alternative is synchronous, which is blocking. That means, you will do nothing else until I'm done with you. Rawr.

[00:18:23] T: Yeah. Although, my understanding is that blocking, doesn't mean it never happens. It's just like, okay, I'm going to save all of these user interactions, until the next time that the queue is free. Then I'm going to jam all of them in there. You're going to get all 500 clicks in one second. It doesn't delete them.

Yeah. The queue part, if I'm remembering correctly, is basically, the next tick area of the event loop, because things that go into the queue are those Tasks. Those things can only run when the stack is free. The stack is where all the things that are maybe kicked off by the queue go and it's like, okay, have a million little things to do. Then the queue is like, “Okay, now I got to wait.” That's the part that gets blocked. I feel like, this only makes sense if you already have some familiarity with the event loop.

[00:19:16] AR: It's a bit like, if I add an event handler, a click handler to a button, right? There is this nebulous event that may or may not happen. When it happens, that click, that event doesn't necessarily fire immediately. It gets put on the end of the event queue, the event loop queue. Then, once, if it’s the next thing, then it will fire and do the thing that I told it to do, is what you're saying, maybe, kind of, sort of.

All right. The stack is the part that when I call a function, that function starts putting things into the stack to be called and do, yes. that's the blocking operation. That is what we call a blocking operation, because that is all synchronous. Then, when we take that function, and we say, “Okay, cool. I have this function that I've made, and I'm going to give this function to an event listener.” We add an event listener for click on a button. That lives nebulously in the heap, until somebody clicks the button. The heap is this nebulous area where things – imagine, if you will, a frozen yogurt shop.

[00:20:38] T: No, no, no, no. It's nice having you on the show. Something, something.

[00:20:44] AR: No. The heap is this nebulous area where things live in memory. They're the things that you are manipulating. Your DOM is in there, like all the functions that are available to you, your scope, whatever, all of the stuff is there in the heap. Until you call it or use it, it exists there. Once you call it or use it, it goes on the stack, basically.

When you make an event listener, it goes into the heap, and it's like, “Oh, yeah. No, I'll let you know when something happens.” When something happens, it takes whatever you told it to do, and it puts it at the end of the queue. Then, once the queue is cleared out and gets to that function call, it then gets put on the stack, and the whole thing starts again.

[00:21:28] AC: It's like being at the airport, when you're checking your baggage. You have to wait in line until the stack is free, AKA an agent to weigh your bag, and all of that fun stuff. If you did something wrong, you have to go back to the back of the line, because you didn't have all the stuff.

[00:21:49] T: I was thinking more like, I have a heap of clean laundry over there. If I take –

[00:21:53] AC: Who has that?

[00:21:55] T: I suppose, you put it on. If you have made a recursive function before, then you already have, in theory, at least, an inferred level of understanding of how all this works. Because when your top-level function calls itself, then, like let's say, you have a recursive function on top of the console log. The console log can't run until the recursive function is done running. The console log is the next task in the queue, but it has to wait its turn. Then the recursive function calls itself, which calls itself, which calls itself. These are all adding more additional calls to the stack. It keeps on adding more calls of itself to the stack, until it hits your base case, where it's like, okay, I know what I needed. Now, I can return back to the function that called me.

That removes that context, or stack frame off of the stack and goes back to the function that called it. It's like, okay, now I have the data I need, so that gets removed off the stack, and so on, until you get to the original recursive function call that kicked off all of the other recursive function calls. It's like, okay, I know the meaning of life now. Then, it gets removed from the stack, then you can move on to the next task, which is the console log.

[00:23:16] AR: Also, if you've ever made a recursive function and messed something up –

[00:23:23] T: Never. Who does that?

[00:23:24] AR: Didn't give it away to end. You will have received something called a Stack Overflow error, which does not mean that you've done something wrong on stackoverflow.com. No. It means that you have put too many operations on the stack. The stack has a limited size. By limited, I mean, I think, there's like, you do a million things or something like that before it goes like, “Huh.”

[00:23:49] T: I think, it's several 100,000.

[00:23:51] AR: Yeah. Once it does, once it reaches that point where you have too many things in it, it stops and throws a Stack Overflow error, because you have overflowed the stack. It doesn't know what to do, and it can't make more room, so it just stops.

[00:24:06] T: I would argue, though, it's easier to make an error on stackoverflow.com. You just post a question, and they're like, “This is off topic,” and close it.

[00:24:13] AR: Yeah, that's true. That's true. You post the correct answer on the wrong thing, and then they ban you for life.

[00:24:19] T: Yeah. This is calling to mind, I saw a tweet the other day that was like, “What's your favorite terminal command?” Everybody was like, “Oh, LS this or RF that.” I was just like, “Ctrl C. I need it all the (censored) time. Ctrl C.”

[00:24:31] AR: My favorite command is there's an alias for please. It's called please. If you're doing something as an administrator, or you want to do something as an administrator, but you forget to click.

[00:24:41] T: It’s the alias for sudo, right? Or “su-doo”, however people say it.

[00:24:44] AR: No. You forget to put sudo, so you type in the command and it goes like, “You don't have permission to do that.” You can make an alias for a thing that called please and you just say please. It does the last command, plus sudo, so it'll run it again. It goes like, “No.” You go, “Please.” It goes, “Okay. Yeah. We’ll run.” Sorry, off topic.

[00:25:06] T: Yeah. I think, lately, IDEs seem to be doing something in the background, where they predict that you're going to create an infinite loop. It'll either warn you before you run your code, or while you're running your code. It won't even bother getting to the point where you overflow the stack. It’s just like, this is going to overflow the stack and it stops you. Which is nice. I have crashed a replit so many times, while I was learning JavaScript.

[00:25:35] AC: What was the end of the knock, knock joke?

[00:25:38] AR: Async, it's now time to move on to this week's picks.

[00:25:44] AC: Amazing.

[00:25:46] AR: Ari, would you like to go first?

[00:25:49] AC: We'll start with what I'm currently playing, that is Skyward Sword, the HD release on Switch. If you like Zelda games –

[00:25:55] T: What was that?

[00:25:57] AR: Yeah. Sorry, you didn't say it right, I don't think.

[00:26:00] T: Can you say –

[00:26:01] AC: The Legend of Zelda, Skyward Sword, HD. The joke there being that I copied and pasted, and it was in very large font in our document. Now, I will never live that down. You can actually do the motion controls, which are better than they were on the Wii, at least. Motion controls are still awkward, so I don't know if you really want to go down that road, but it's an option. It's obviously, it's not the best Zelda game, but it's still fun because it’s Zelda. Yeah. I'm halfway through it. I'm enjoying it.

Then my second pick is just something cool that I found out this week that I just did not know previously, and that is that you can use Command or Ctrl depending on what operating system you're using. Ran a Ctrl K and that is a shortcut for inserting a link. No more right-clicking. You're welcome.

[00:26:59] T: Like you mean to turn a text into a hyperlink, right?

[00:27:02] AC: Yeah.

[00:27:03] AR: Interesting.

[00:27:06] T: Wait, I need to go back to the best Zelda thing, because you said it, we all obviously know what the best Zelda game is and I'm like, “I don't.”

[00:27:12] AC: Oh, no. I mean, there's a range. There's a spectrum. I wouldn't say that – I'd be surprised if it topped of anyone's list.

[00:27:19] T: I did not enjoy flying in that game. I had the one [inaudible 00:27:23].

[00:27:23] AC: Flying was so hard.

[00:27:25] T: It was so hard. I'm convinced that the gold Wiimote weighs more than the regular. I haven't actually tested it, but it's like, my arm is sore when I play that game.

[00:27:33] AC: Also, they did not adequately train you. I had to look it up to figure out how to efficiently gain altitude. It turns out, you flap it like a bird, which makes sense once you know, but when you don't it, yeah.

[00:27:46] T: They made you go through the training so many times. It was like, at the start of the game, I was like, put it in the game after I like the game.

[00:27:54] AR: I have never really played. I've started one Zelda game and that's it.

[00:27:59] AC: It was really nice having you here, Alex.

[00:28:01] AR: Yeah, I know.

[00:28:01] AC: Bye.

[00:28:02] T: Skyward Sword is actually the only Zelda game I've ever finished.

[00:28:06] AR: Would that make it your favorite?

[00:28:09] T: No. Breath of the Wild is my favorite. Which is funny, because I don't usually like Zelda games. I usually don't like open world, but I really liked that game. For some reason, I'm like, “It’s really relaxing.” Even though Ari is making this disgusting face, I feel she'll understand that I got to the final boss level. Then I have 5 million micro-tasks, collectible things on my queue that I had to clear out first. I don't want to beat the game. Then it turns out, I can't go back and finish every little thing. I just never finished the game, because I was like, I have such a long to-do list.

[00:28:38] AC: Relatable. I should mention, I got all of the korok seeds. I'm so proud of myself.

[00:28:44] T: Oh, my God.

[00:28:45] AC: All 900.

[00:28:48] T: I remember, you messaged me that and I was like, “Jesus Christ. All of them?”

[00:28:52] AC: By the way, you get a golden turd. That is your reward.

[00:28:58] T: That’s okay. I would hear that everywhere. Yeah, I don't know if I could commit to that. Just like, I couldn't commit to digging up all the – I don't know what it was, but okami, there's this thing where you have to dig holes all around the country, but some of them only appear at night. You had to happen to be looking in the right place at the right time to see it. I was like, “I don't want to do that.”

[00:29:19] AC: Okay, enough Zelda.

[00:29:21] AR: Yup. Tessa, what are your picks this week?

[00:29:23] T: My pick is this British candy. I really like sour gummies and gummies in general, but if you were wanting to find one that didn't have corn syrup, for example, or didn't have artificial colors or flavors, that really limits your selection. I still haven't found a gummy that fits that criteria and is actually sour.

Yeah. I saw this thing called Candy Kittens the last time I was looking for candy and I was like, “Oh, those look interesting.” It's an assortment of fruit-flavored gummies that tastes pretty different to other gummies I've had before. They come in all kinds of flavors. My favorite so far is the sour watermelon. It's not sour. It's not super gummy, but it just tastes – I don't know how to describe it. I don't really like this word. It tastes wholesome. It has a wholesome flavor. It doesn't really taste – A lot of candies, I feel like, have a very flat, or tart sweetness. This doesn't have that. It's more of a gently, sweet gummy that's not super gummy.

When I was looking for the link, I saw that they have a web exclusive gourmies bundle that comes with the candy kittens bucket hat, and I just thought that was really funny, so I added the link to that, too.

[00:30:33] AR: Awesome.

[00:30:34] T: There's also no palm oil in it, which I didn't know was a thing that could get added to gummies. When it's added to chocolate, often, I find it has a weird texture and aftertaste. I was like, “Okay, that's nice.”

[00:30:46] AR: Interesting. Good to know. My picks this week are Olivia Beaumont is an artist that we really like. She does a lot of paintings of stuff. We have several prints of her work at home. We have a sloth with a chalice dressed up in a suit. I think, we also have a badger. She does really interesting portraits. We found her art in Savannah, Georgia, when we were down there, and we instantly were like, “This is really weird, and we love it.” Shout out to Olivia Beaumont. Go look at her work. Maybe buy some of it if it intrigues you.

My second pick this week is the board game Obscurio. It is a board game that some friends of ours introduced to us. Imagine, it's a bit like Mafia, or Avalon, or Resistance where there's a traitor among you and you have to try and figure out who the traitor is. Then, also, you're attempting to escape with a book. The book is trying to help you escape, but the traitor is actively making it not possible for you to, actively working against you to escape.

Then you have to choose a door. It's a whole thing. There's code names, Dixit vibes, but then, there's also Avalon vibes. Then, there's also – It's really interesting. It's a really good game. You should play it with five people, is the thing. It has to be played –

[00:32:20] T: Like exactly five? Four and a half.

[00:32:23] AR: At minimum, five. We did it with four and it worked, but we were like, “Yeah, no. Really needed another person for this.” Those are my picks for this week.

That's all for this week's episode. If you aren't following us on Twitter, head on over and find us @enjoythevuecast. If you like cats, you can find us @enjoythevuecats. Be sure to subscribe to the show, if you aren't already. If you have time, you should go to the place where you get your podcasts from and leave a review, so that we look good. If you don't like the show, don't leave a review. That's fine.

Finally, the first rule of Vue Club is, be sure to tell at least five or six colleagues about Vue Club. Thanks for listening. Until next time, Enjoy the Vue.

[ Music Starts and suddenly cuts out ]

[00:33:28] T: I sincerely hope someone is out there telling the same 5 to 6 colleagues every week, “Did you listen to the show? You should listen to the show.” and they are like, “We all listen to the show. We’re all subscribed, Alex, stop telling us.”

[00:33:38] AR: [ Laughter ]

[ Music plays out ]

[END]