about 2 years ago Syntax Podcast
Promise Flow Control, Concurrency, Libraries, TypeScript and Deferreds - Part 3
- 00:28 Going deeper into promises
- 01:34 Using with resolvers for promise flow control
- 02:47 Using with resolvers for streams
- 05:33 Need a class to handle both streams and promises
- 06:11 Fetch returns two promises
- 09:06 Controlling promise flow
- 12:20 Concurrency and throttling with promises
- 15:14 Retry logic for promises
- 16:52 Typing promises in TypeScript
Fetch returns two promises
Wes Bos
You may be streaming in the result or using server sent events error is an instance of error and or if error has a message property, then you you just know exactly what the error type is.
Wes Bos
they are streaming it to the browser. So I used to think, like, while you're using chatty gpt, they're just doing this, like, fake typing to make it feel real. Mhmm. And the actual answer to that is that's actually not true. It's callback based architecture, How do you how do you So I kinda want both. So I'm I'm sure somebody has already built that. It wouldn't be it wouldn't be too tricky.
Scott Tolinski
if it's also creating the code. If you tell it to create code and comment the code, it always puts the comments below the code it just wrote. Because
Wes Bos
is that it requests something from a server, and the server is going to come back to you immediately And lastly, there's no way to you can use a the OpenAI result, generating the actual output, the promise itself along with its controls, It was very easy before. It was just like 1 more level of indentation
Wes Bos
with
Scott Tolinski
isn't great at commenting
Scott Tolinski
And I I even I've been sorry. Go ahead. No. And that's one of the reasons why ChatGPT
Wes Bos
JSON, but you are also we did a whole episode on streams.
Wes Bos
is for Scott JSON.
Scott Tolinski
unless it's writing the comments first, maybe you could tell it to do that. It it's kind of like coming up with what it's trying to do as it's doing it. Yeah.
Wes Bos
Flow control.
Scott Tolinski
code
Concurrency and throttling with promises
Wes Bos
But it is and then you can write a type guard that will check for either the reason or the status property
Wes Bos
between promises, prompts all settled in these little helper functions, I find them to be more than enough.
Wes Bos
But, like, something like p map will allow you to the word synchronous in in callback of its resolve and reject methods.
Scott Tolinski
And having that all built in is really, really nice. Yeah. I have not I mean, it's funny. I I I have used And then
Wes Bos
that will like, your Internet provider will probably shut you down or you'll hit some Scott, like, thing. If you send 10,000 requests to download files to an API, you're probably gonna get in trouble.
Wes Bos
create an array of possible promises.
Wes Bos
but I don't use it all the time. And I don't use it anymore because
Wes Bos
So often you will only be allowed to create And Yeah. Sometimes these APIs will return to you how many calls you have left generic to say this is what the error will look like. And that is really nice because now and then you're you're not doing the whole, like, as they are
Wes Bos
run 5 at a time at most. And what it will do is it will simply just it'll fire off 5. And then as as as the first one finishes, it goes down to 4, and it starts the next Node, and then it starts the next one. That's that's better than chunking because chunking will do, like, 5 at a time, wait for them all to finish. And then another Another 5, wait for them all to finish. Yeah. Whereas, like, concurrent
Wes Bos
Concurrency throttling queuing. So headers back. And in that, you can check for the header response code.
Wes Bos
things, the actual type there.
Wes Bos
So loop over
Wes Bos
And you give all of those to npm map and you say,
Wes Bos
I need to make a whole bunch. It's almost always with fetch. You know? I need to download a whole bunch of files. I need to hit an API a bunch of times to get all of this data, it's literally
Wes Bos
specifically
Wes Bos
there are some really nice packages out there,
Wes Bos
and you find yourself ESLint a situation where it is way too slow to do them in series Node after another.
Wes Bos
not possible to run them all at once because
Wes Bos
Nice. Yep. It's pretty handy. I used to use this thing called Async JS
Wes Bos
p map, p limit.
Wes Bos
mapping will writing, like, a wrapper function that will do collecting and give you a tuple error first, data second.
Wes Bos
like, p limit, p throttle, You can extend that a little bit further I find myself getting into this area a lot where coming up with the result Yeah. And firing it out the door before it even knows that it is done.
Transcript
Scott Tolinski
we got the basics. We got the intermediate kind of syntax stuff.
Scott Tolinski
We're gonna be talking about, you know, practical stuff with fetch. We're gonna be talking about flow control, concurrency,
Scott Tolinski
throttling, queues, all of those types of things. Basically, I I got actually got to wait until promises landed in the browser before I had to deal
Scott Tolinski
Oh, welcome to Syntex. On this Monday, hasty treat, we're gonna be hitting you with part 3 of 3 in our series on promises. We're gonna be talking about some new stuff, like, with resolvers.
Typing promises in TypeScript
Wes Bos
I think there's a type called promise all settled sometimes APIs are not based on pages. They're based on cursors.
Wes Bos
TypeScript helper, and that will take the the promised part off and and give you the, This is just like a a TypeScript thing in general, and I bet this will be fixed soon, but I've also been saying this for a while.
Wes Bos
on there.
Wes Bos
the filter does not actually responds as soon as the server comes back with its headers. So the way that a web request works it you can think of it as that.
Wes Bos
if body, of a promise, and that that's a little bit of a pain as well. That's it can be nice you you get the the initial headers first. And then if you want all the the whole payload synchronous, meaning or or or series is often a good word for that because
Wes Bos
to display the data,
Wes Bos
to your filter to actually tell TypeScript, Node. I am I'm filtering it down. And I run into that a lot with promise dot all settled because it will return again the fulfilled and the rejected values. And if you wanna just filter for Awesome. Alright. Well, thanks everybody for tuning in. Tweet us your promised tips at Syndax event. We'd love to hear them.
Wes Bos
And if that's the case, like, you're using, like, a a type of from the Vercel. Whereas, like like, chat g b t, a lot of these things are Wild. Yes. I think that's it for promises. Wild world. I'm impressed that we're able to get 3 episodes out of this, but there's a lot of funky stuff to learn about promises, and it's it's good to know. Can you imagine if we would have had to do this episode on So Where this is is really useful is And if that's the case, you can wrap it in the awaited what you've had to do is you had to create a variable outside of the scope of that promise. And then when you get inside of it, you have to update the variable that's outside.
Wes Bos
Exactly. It'll eventually resolve to that amount. And a couple times, I've needed to
Wes Bos
then you'll have to write a quick little type guard. And
Wes Bos
a an array in typescript and you try to filter it,
Wes Bos
like, like, like, the file system APIs didn't have promise versions of it, you had to, like, wrap their callback based APIs in more than 60 in this time span or don't run this function There's also, or or run it at most once every 1 minute. You know? And that kind of stuff can be really, really funky or retrying is another one. There's there's libraries out there for run this promise. And if it fails,
Wes Bos
to use that. In the last episode, we talked about that, And let's talk about, like like, why might you want that? I've talked about this on the podcast before JS the promise, add a type guard
Scott Tolinski
Yeah.
Scott Tolinski
but then the promise itself will return I did not get it. Yeah. I
Wes Bos
by default, if you don't use any, like, patching libraries or anything like this, this list of 10,000 files and return a function that will download a file once it has been triggered.
Scott Tolinski
that type.
Wes Bos
You're like, I don't care about the promise part. I want the type of user.
Wes Bos
the rejected to display some errors and you wanna filter for the successes each of those strings and return a promise, p debounce.
Wes Bos
if it does return an error, if you wanted to access a promise await inside of a while loop, which can be useful some information. It might not be all of the information, but you do get the initial and they're all, like, little utility libraries. Quite honestly, I forget which one I need every single time, and I have to read the docs.
Wes Bos
If you have You can't use,
Scott Tolinski
with Promises. I I just used callbacks until then. I was like, you know what? This doesn't seem worth it to me. That too. Yeah.
Scott Tolinski
promise libraries before promises existed?
Scott Tolinski
Take
Wes Bos
Promise that all settled filtering.
Controlling promise flow
Wes Bos
if you want to just another API You can return. Most commonly, we all are doing and then you'll wrap the ad in a promise to all settled to get all 3 of them. Those run concurrently, meaning they run at the same time. It's not technically. We have a whole show on that, but you listen for what's called chunks. I know, Scott, you're working with the get user the webcam API right now to stream in video chunks. Is that what it is? Yeah. Yeah. And I'm sending them to over HTTP to a Wes, Or it still does. And it's it's not a new concept in in programming, but it's not something we've had in JavaScript. And there's lots of libraries out there that were Mhmm. And you you can't do it until you have the cursor from the the page before it.
Wes Bos
and I no longer have to to keep doing that. Right. And, also, in cursors, that's something we haven't talked about a lot as well Wes 60 requests per hour. So you wanna say or or or 60 requests per minute. So, like, okay. Well, don't run
Wes Bos
there's no more. And often, the only way for you to tell that is a certain amount per Sanity.
Wes Bos
and doing them all at once with promise to all settled, which is 10,000 at once. There's some sort of middle ground, and we'll talk about that in just a second.
Wes Bos
as you're doing it. And that is a good use case if you wanna do one thing after another. Like, we we talked about me downloading 10,000 files a couple episodes ago. I initially had wrote a four loop, like, a map. If you have an array of, like, names and you wanna fetch like, you have Scott, Wes, and CJ, and you wanna go to the GitHub API and fetch all 3 of our profiles, if you want to instead of having to pass your work into a promise Mhmm. So often when you're you're doing a bunch of stuff, what you'll do is you'll make a function, you'll return a new promise, and then all of the work needs to happen inside of that. And sometimes it makes a little bit more sense to The first Node, and then you immediately from that, you return response dot JSON, and then you have access to the actual data. And that's because that's that's the way servers work. You about the output result, you can use the promise that with resolvers to every I don't know. You can Sanity how many seconds, but imagine it was 3 seconds of video. You get a chunk every 3 seconds. And then the way that it works is you you put those chunks into an array, and then you wait for and promise that with the resolvers will will do that for you. It it Scott of surfaces the resolver and check methods alongside a specific function, as it's coming up with the result and as it's These will allow you to only run them at after a certain amount of time or at most every 2 minutes.
Scott Tolinski
So you could say, hey. Go off and fetch page 1. Alright. Page 2 has come back. Sometimes what they do is they give you, like, a, like, a key for what the page JS.
Wes Bos
the ones you need, like, a cursor ID You wanna return that from a function so that you can wire it up to buttons. You may wanna pass it to a success
Scott Tolinski
So then you pass that into the next fetch call, then you like, the data that
Wes Bos
wait for the the next item to come through.
Wes Bos
Meaning that in order to get the items after
Wes Bos
they don't know. You just you just keep going until if that's not the case, they don't tell you how many are allowed. They only tell you if you can't run it. If that's the case, then you have to, like, use one of these libraries to and put in the hard limits so that it won't run it too too frequently.
Scott Tolinski
While loops. Yeah. I don't find myself using while loops that often, but the other day, Node did come up, and I I while looped it. That's for sure.
Scott Tolinski
Yeah. I I can think of, like, some APIs too. They return things in pages.
Wes Bos
often what people will do is you'll map over narrow the types for the items that you filtered it in, which is annoying. So you have to
Wes Bos
in between doing them in series, which is Node after another, you listen for chunks, 8 or 10 words into the response, and then it just clears it and puts something different in. And it must be because
Wes Bos
And they're like, oh, well, there's nothing here. I must have reached the end of the road, A while loop. Again, a a while loop is not something I reach for all the time, probably a couple times a year, but you can and it gives you both the stream events, and you can await it. Yes. Because
Wes Bos
inside of a four loop. This makes everything throw a 500 milliseconds wait wait in there, you know, and then and then fire it off.
Scott Tolinski
precedes
Wes Bos
First of all, looping over promises, you can use a four of loop and you can await and and when your call amount refreshes. And if that's the case, I'll just look at the header and say, alright. If I'm out of calls,
Using with resolvers for streams
Scott Tolinski
process, which is then collecting them all in a temp file.
Wes Bos
in streams. If you want to be able to JavaScript often means that it's blocking.
Wes Bos
you can say, like, on error and on cancel of the media recorder is equal to reject. Oh. And then on unfinished, there are a, like, util Scott promisify.
Wes Bos
which is basically Sanity Sohras has, I don't know, probably 15 different p dash But in our case, you simply are just, like, pausing the four loop like return a fetch request that goes to those those 3 URLs, a type the rejected value
Wes Bos
the actual promise.
Wes Bos
with streams, the way that it works is that you you get a stream, always be running 5 and always tearing off a new one as soon as there's a single spot. Yeah.
Scott Tolinski
a stream before as a promise,
Scott Tolinski
a stream rather than
Scott Tolinski
libraries
Scott Tolinski
to collect
Scott Tolinski
once the process is overriding that temp file to a video file with FFmpeg.
Scott Tolinski
every single one of their search APIs returns
Scott Tolinski
you can't just, oh, async await. You can't just await for the data to come in. And that's obnoxious as hell when you're doing like, oh, let me just do a quick HTTP call, and I don't wanna have to return the stream back to the UI. I just wanna collect the data and send it to the UI when it's done. Yeah.
Scott Tolinski
like collect stream to promise. Because when working with Braintree, on into it. I have deferred
Wes Bos
it to be finished. And then when it's finished, you take all those chunks and you put them together and you get a a video file at the other end. Right? Yeah. That streaming API is based on events. It's like on data. Right? Mhmm. And inside of a promise, but that's 1 Wes nested promise, one less weird scoping issue that we need with this sorta helper method. Yeah. And it it's actually funny, Wes, that you say that because I've used
Using with resolvers for promise flow control
Wes Bos
previously, when you work with streaming APIs, it's it's not a promise. It's chunks. But if you just care of the body of the response, you have to sometimes wait a little bit longer for all of that to to sort of come in. So most likely, you're checking for a response code. You're getting Scott text or it matters for the data that you're trying to get next. So that'd be a good reason to do a follow-up. Yeah. Yeah. That that's a great use case because sometimes the API will tell you how many pages there are, and you can fetch them all at once. Mhmm. But often, they don't know. You just the way that it works is that you you create a media recorder, in TypeScript. It's it's built in, and you'll often see that in TypeScript. It's promise sometimes you wanna take the promise off. Like, you wanna unwrap it. Like, this function returns a promise that is of a user.
Wes Bos
and its resolve and reject methods outside of the promise
Wes Bos
just made for simply making a deferred.
Wes Bos
instead of passing your work into the promise, you want to pass on I use Raycast.
Wes Bos
That works really well. That whole pattern is called a deferred, and that's something we've had since jQuery had deferred for a while.
Retry logic for promises
Scott Tolinski
but I haven't used any of these p tools before. They're often scraping for me. It it's funny.
Wes Bos
that you want. And if you if you fetch something you give it the resolve method, and you can you can pass the the chunks to that. So
Wes Bos
run it from a function that returns a promise.
Wes Bos
API only allows you to Right? And people have often wondered, like, why why is fetch 2 promises? with a specific type, you'll see its promise square bracket, whatever. And if you put in a weight in front of it, it will unwrap the promise and actually give you the real type. Yeah. And and so to be clear, the reason why you do that promise with the brackets around it, that is essentially saying, hey. This thing does return a promise, That's actually, I've been wanting to make this for a while. It's like some sort of, like, custom class that extends Let's talk about fetch. We know we've talked about fetch before. Fetch, you pass it a URL, returns a promise. The kinda interesting thing here is that the first promise of a fetch It would have been there's so much like, with the promise libraries back in the day, you had to, like, wrap everything. Even in Node. Js before,
Wes Bos
angle brackets and then the actual type of the value it it's not again, it's not something we could never do before.
Scott Tolinski
throttling and debouncing,
Wes Bos
But
Wes Bos
TypeScript and promises. This is the last thing we have here is get the type
Wes Bos
So maybe, maybe that's where you'll you'll have to hit it. Or, like, and that was kind of slow because you download 1 file, you wait for it to finish, then you do the next Node, then you do the next one. In in reality, there's some probably some sort of use case So, yeah, currently doing that. That's that's really cool because with in the browser with media recorder, the next time you fetch 1, the result is empty.
Going deeper into promises
Scott Tolinski
Now here's what we want. We wanna learn how to get even deeper with this. And if you're getting deeper into any type of new topic or code, you're gonna make mistakes. You're gonna cause bugs. Potentially,
Scott Tolinski
That's Wes e n t r y Scott I o forward slash syntax.
Scott Tolinski
Sign up and get 2 months for free. And, seriously, just, just give it a rip because once you get used to those dashboards and once you get used to those dashboards in your your project, in your application, it's really hard to live without that visibility
Wes Bos
Yeah. So retry it up to 6 times. And if so, then finally reject.
Scott Tolinski
and to just kind of be flying blind on what your users are actually hitting in your site. So let's get
Scott Tolinski
you're going to end up, with some performance issues as well. And to track all of that stuff and make sure that you have a handle on it, you're gonna want to use [email protected].
Scott Tolinski
In talking about with resolvers, which is newly available. So, Wes, do you wanna I I've not used with resolvers. I'm super interested in what this is and and how to use it.
Scott Tolinski
the first thing, deferred promises.
Scott Tolinski
the starting of this episode long enough. We're gonna be talking about
Need a class to handle both streams and promises
Wes Bos
the actual end. Like, a chat g p t would be a good example. Right? I care about the end text that I get from chat g p t, but I also wanna display the text as it's being streamed in from the server.
Wes Bos
sometimes I care about both. I want the output, but I also wanna listen for just how to use promises in in TypeScript. Right? Because promises are a generic flow through promises? They just rolled out Claude Haiku support. Mhmm. And I noticed using the Claude one, sometimes it's, like, and internally do a type assertion, and you can say, alright. Well, imagining more of the sentence, it goes, you know what? Those first 8 words I said were not Could be a bit better, and it it replaces it. So I thought that was kinda interesting with with streaming.