Asynchronous Programming in Dart - Learn About Future, Stream and StreamController in Dart

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi everyone and welcome to this chapter of dark crash course in this chapter we're going to talk about asynchronous programming and I know a lot of you have been waiting for this chapter but I've intentionally kept it until this point to talk about asynchronous programming simply because talking about this topic requires us knowing about a lot a lot of other topics and we can't just jump into it from the first chapter so I'm grateful for you for being so patient until we get to this chapter I know for instance the mixing chapter was an important chapter for you as well but the more advanced we get we have to pretty much wait until almost the end of the course to talk about these Topics in this chapter we're going to talk about mainly Futures and streams and I know for sure that this topic is a little bit scary to some developers especially if you're a little bit more beginner maybe to Dart and but I'm going to try to break streams and future actually Futures first and then streams down as much as I can um but there is also a limit to how much we can break things down otherwise this video could go to maybe four or five hours long um but I really do my best to break it down as much as possible so we go into details about how Futures and streams work in art let's get started I'm going to bring up a terminal window in here and let's go in here and say that we have a new application let's say Dart creates with a template of console and we say asynchronous async actually what should we call it let's let's go async currentness programming something like this I wonder if I wrote it correctly a sing Corona yeah it's a long word okay and let's go into there async with Visual Studio code gonna get rid of the terminal window here and let's go to the workspace Json zoom level of six we usually do and let's get rid of the first uh Dart file in there and create example one example one Dart main function of course we're going to get rid of the Explorer in terminal FS watch and we're going to say example one there's a little bit of configuration always in the beginning of chapters and it is a little bit tiring but what can we do this is just something we have to do to set up our project so let's get rid of that Json file and we can then get started so let's talk about Futures so what are Futures Futures are pieces of functionality that will complete their work in the future as their name indicates a usual function that you call you take some input pass to the function and ask the function to do some work and then when the function is done you get the result back so let's say that I say um strength get name so this is a simple function and it says Fubar and in here I say final name one is get name and then name two is get name and then print name one and print name two so uh what's happening in here is at line number two the program will stop execution of this the main function and it will literally jump from here line number two to this function and it says Ah this function is returning the value of Foo bar then takes that value of Fubar and brings it here and literally says name one is fubar then it will continue to line number three so that's a very huge distinction between how normal functions work and how Futures work so remember normal functions when you call them the application stops executing the caller function in this case the function that's calling the get name function is main function so execution will literally stop in that function until get name returns okay so then you can go to line number three and again it will jump here return a value and then it will continue after that okay however if you call a function that returns a future the execution of the caller function will just continue it doesn't really care when the future ends unless she asks you ask the application to wait for the results okay and that's done using the await syntax we're going to have a look at that now so let's remove these from here and let's create a function that returns a future of string instead of a string and we say get username okay and here then we have different ways of calculating this future so one way I'm going to show you a lot of ways actually one way to do that and I'm going to show you a lot of ways actually to create functions like return a future in this example but one way is to Mark the function as async once you do that then you can literally turn this into a normal function so you can see in here we're literally saying return John Doe you see this is just like if you had a simple string function like this except for the future and the async part okay and if you remove this async then you can't do this anymore so if you want to return a value just like you would in a normal function and just turn your function into an async and then you can do some calculation in here and then return a value but usually that's not how we do things I'm just showing you that if you have async like this in here function then you can return a value okay and to be honest with you this is a completely normal syntax and in here you can actually do some asynchronous work as well that will complete in the future and then you return a value depending on those values that have been calculated in the future as well so but just know that if you have async like this append it to your function signature then you can literally return a value like this okay there we go that's one example so then in the function that calls this sorry in the function that wants to consume this function which returns a future then we can go and say print and we say get username and you can see this is not really going to work as we want because the return value is going to be an instance of future so whenever you get an instance of a future you just know that it's not consumed yet so you need to consume it in order to actually get its value but how do you consume it one way to consume a future is by saying await okay and wait what it does it calls this function and it awaits and actually waits for the result to come back and then it will give you that string which is inside the future so a weight dissolves and resolves this future pretty much however in order to use a weight then you need to have an async function as well so like this all right so if your main function that is using the await keyword inside itself doesn't have and the async keyword here then it can't use the await keyword inside all right so that's one way to consume a future and you can see the result printed right here okay let's create another async function and we're going to call it say Future IT returns a string as well we're going to say get address like this and then in here then we're not going to use async but instead we're actually going to compute a future so let's say we just want a future a string that simply returns a value just like we did in here however we're not going to use async okay so let's say we return a future value as you can see in here future value and then you say one two three uh mainstream for instance and now that we have this function we can go and consume it so let's see if GitHub copilot can help and there we go we get address one two three mainstream okay so this is another way of creating a future in this future I mean both of these functions though they're saying that they create a future but they're simply calculating a string for instance in here returning it immediately so there's really no waiting involved in here so there's really no heavy computation happening okay so let's create another function and we're going to say this time we want to feature a string that gets a phone number but we want to do it and we want to actually do the calculation in one second so this is one of the points of having a future in that you can do something in the future okay so let's say future string and we say get phone number okay and we say this is a function that returns a future with a delay and we say delayed like this I'm going to bring it to the next line and for the duration we we create we say const duration seconds one okay so in one second and then we say the computation happens in here inside this function and we just return a dummy phone number just like that boom let's see uh oh the list of parameters we forgot about that there we go okay so this is another way of creating a future you say future and you want to delay it by a second and then after that second elapses you get this function callback and then whatever you return from here will be returned from your future so you could actually mark this as future string okay four just to be more explicit what this actually does because if you say future string in here and then go and return a number then you will get an error okay it says int isn't really a string okay so uh that's an example and we can go ahead then and print this result to just be printed the result of these two other functions and you can see the result printed in the in the console or in our terminal okay another way of creating a future would be to say future a string for instance and we say get City City like this and then we say it's an async function and in here you can actually delay the return of your value by using future again so let's say we say New York okay but before this we want to wait a second how do we wait a second in this function well let's say that you have a future that is delayed and we say const duration seconds one okay so you have a function sorry you have a future in here that doesn't produce any values at all so let's say if you say final blah it will be a future of dynamic because in this function like we actually didn't pass this function in here so it's literally a future that doesn't produce any values okay how do you wait for it though because this this guy wants to wait a second right but if you go in here if we go and say prince get city in here you will see the result will be printed uh there we go it's I mean we had to wait a little bit because get phone number was delaying things so if I comment out get phone number you can see get City prints out its result immediately but why because we had a future delayed in here by one second but the thing is we have a future in here but no one's waiting for it and that's the point of Futures there's just an instance of the class future is a class okay however in order to actually kick it like kick start it to say that I want to wait for this future to do its work then you have to say await okay so remember that you have to await for futures to get their values okay or actually I would say you have to await for futures to kick start them okay not just to get their values because if you have a chain of Futures you can still use like the then function on them as we'll soon see and get the value of the previous feature and change it to the next future so to get the values you don't necessarily have to say oh wait but to kick start a future and grab the final value of the future you have to use a weight okay good this was another example so then let's go and create another function and this this time around is going to be a simple function of future and we say get Country and this is another way of creating an async function you can literally say it resolves to a value and that that is simply possible because we have async in here right because if you remove this you can't return this you have to say future dot value like this but if you want to Simply return a value as a future then you can mark it as async and then return your raw value as you can see in here okay and the last example I want to show you is simply using future delayed and async so let's say future string and then we say get zip code I know a lot of countries don't have zip code and it is postal code for instance in the UK and postcode here in Sweden but zip codes used in the US so let's just go with that and in here what you can do is to have a future and you say delayed all right as we did before let's create our duration so we say duration seconds one and then in here we just say a function that returns one two three four five okay so this is one way of creating that but we've already seen this example but I just want to show you that you can also Mark this as async if you want to so a function that returns a future and like this it can also be marked as async but this really doesn't do anything okay because ins this async is literally placed in here so that you can either return a raw value of this type which is string or that within this function right here you can use the await keyword but we're not doing either so this async isn't really contributing to anything so you can literally comment it out and your function will still compile all right so I'm just going to leave it like this with the commented out code or actually let's just remove it and let's just put a comment in here say async keyword doesn't really contribute with anything here okay and then let's go and consume these so after it get City we have get country and get zip code so get country and get zip code and let's put the results in here and then you can see all of them are pointing out the results okay so consume and get the latest value or the last value of a future or a future chain using the weight keyword okay good done with example one let's create example two uh example two Dart and we need to fix our FS watch as well to watch example two in here or execute at least example two upon changes in this directory good um now what we're going to talk about is future error handling all right let's let's demonstrate that so what happens if a future actually errors out how do we handle that let's say we have a function that returns a future of string actually you know what I'm going to copy paste that simply because this part is something that we've already done in the previous example so you can see here we have a class and it implements exception it's called first or last name missing all right and there is a separate chapter that I've created in a dart crash course for exceptions and error handling so you can watch that and this won't be any surprise for you that we can create custom exception classes then we have a future of string function that is called get full name and you can see it has two required name parameters first name and last name and if any of them is empty then we throw an exception you see we're in a function that creates a future but we can throw an exception right there and when you throw an exception this future will error out so that your error will be embedded inside this future so the future class can either carry with a a value or an exception and in this case we're saying that it's a future that either carries with an a string or an exception if first name and last name are empty or one of them is empty we throw an exception otherwise we just say return a future dot value and you could change this to an async function and literally in here just return this raw screen so and that's also possible it's up to you okay now that we have this how do we handle errors so let's say that we turn this function into an async function so that we can await on the result of this function so we say get full name and for the first name we say John and for last name we say do all right actually it's a name parameter so let's say Nate last name and we can await on it and then we print it all right like this like this like this and then we will copy this code and then do another execution of it and this time around for first name we just return sorry we just pass an empty string so let's run our application you can see in the first instance we get John Doe but in the second instance or the second execution in here since we're passing first name as an empty string then we're getting an unhandle exception in here and it says instance a first or last name missing exception all right so now our FS watch is kind of broken we have to run if it's launch again to get it to work okay there we go so how do we handle errors and or sorry exceptions and you can see in here simply because we're using a weight what happens is the code hits line number three and it says oh I have to wait for the result of this function then it stops the execution of this main function right here at line number three goes into this function gets the future awaits for the result or waits for the result then it says John Doe okay I'm gonna put John Doe in here it says okay I will print Janda and then it will continue so a weight has that effect on your code that it it basically stops the execution of the program or the calling function at least at that point in time all right it goes here and says okay this guy is going to throw an exception and then the exception is thrown I think at line number nine or ten it should be let's see is it nine or ten uh here it says it is thrown in get full name but inside main is at line 10 there we go at line 10 right good so we know that that throws the next session but how do we handle it well you can see it is a simple function that we're calling it here so you could put it in try and catch so let's say try like this and then we say catch or on first so we basically catch our exception then we take our print statements like this and we put them in try and then we can print let's say print and we say first or last name is missing all right and then we Kickstart FS watch again and let's see and now you can see you get first or last name is missing so this is a traditional way of catching your exceptions and it works really well in this particular example because we're awaiting on the results of these functions okay so it's kind of like a normal function that you're calling normal function get the string and then if it throws an exception then we catch it all right so that was that example I mean there are other ways of catching uh exceptions that are thrown inside uh Futures and we're going to talk about them soon so let's go to example three like this and our FS watch as well let's fix that up here okay and then I'm gonna put a main function in here and I think we can turn our main function already into an async function because we're going to need that so like this okay and get rid of terminal okay in this example we're going to talk about future chaining and this is something that scares a lot of people but I don't know why um it's very easy but to be honest with you I'm a little bit biased because I've been doing reactive programming for God knows maybe about six years I would say it's been a long time six seven years I would say and it's been it's been a very very rewarding Journey for me to actually get used to a reactive programs so I'm quite biased when it comes to it because streams and Futures are usually using reactive programming and I find it very very easy to work with but a lot of people have difficulties with it and simply because just talking about Futures and streams scares a lot of people so that feeling of being scared prevents those people from actually digging into how asynchronous programming works it's not that asynchronous programming is difficult it's just because a lot of people are scared of it and they don't they don't want to get into it so they just think it's easier to hate it than to learn it so I'm here just to tell you that it's very very easy once you get the basics of it nailed down all right and let's go in this example and talk about future chaining the concept of future chaining means that you have a future and it calculates a value and that value is then fed into another future which perhaps conserves that value and produces another future so a future within a future so future chaining is the is the possibility of feeding the value of a future to another future and let the second future complete or continue its work with the value that was fed from the first future and so on and so forth so this feature chaining can just include maybe 10 20 Futures Each of which completes feed this value to the next future and the next future continues and to do its work using the value of the first feature or the previous Future Okay so let's see in here let's say that we have a function and this is just for demonstration purposes so we say we have a function that returns an integer and we call it calculate length and I can't the length of a string simply you can calculate it by returning it but in this function we're just doing it for the purpose of demonstration okay so let's say string and we get a value and in here we just say okay we return a future that is delayed by a second and then the result of this feature is the length of that string that we fitted okay then we create another function and we say future string and we say get full name like this and we delay this as well let's say delayed like this and we say const duration seconds one and like this and the value that we return is John Doe as you can see in here so one function that returns after a second and returns John Doe and a second function that calculates a string and sorry to calculates the length of any string okay so how do we first call this function and then feed its value to this function well there are different ways of doing it let's say that our async sorry our main function is an async function so what you could do is to say okay a weight we want to await the result of this function calculate Lane length Okay so we say calculate length and then in here we want to pass this function to it to this but this function returns a future string but this function accepts a string so how do we do it well we await the get full name like this okay and we say final length like this and we can print the length so you just await on get full name and the result of that will be passed into calculate length and then after two seconds you get the value of 8. so this is one way of doing it however the one that we want to demonstrate in this example is to say a weight and we say get full name okay sorry actually let's not wait let's not make things complicated so let's say get full name and we want to pass this get full names result into calculate length and you can do that using the then keyword and this is future chaining so this value will be of any type that this returns so this is the value that actually is coming out of this function okay using the Zen keyword and I can see then can either return the raw value as a future actually it should say future or there we go so it says in this function you either return another feature or you turn a raw value so in here you could just say one if you want to and the result of this will be a future of int so blah and you can see blah is a future of int because here we just return it but if you say 1.1 it will be a future of double however we're not consuming this value or if you set value since value is a string which is the result of get full name blob will be a future of string but what's important about the then function is that you can return a future from it so in here then we can say Okay calculate length and note that I'm not doing a weight okay it's because this future will be returned from then and this whole thing you can await on and we say now we get a future of int and then we say await on it and we say length and then we can print it to the console okay there we go and we're going to get the same effect after two seconds the value of 8 is printed to the console okay so this is how you do future chaining using the then function and in here since this is a I mean if you don't wait on it then you get a future of int and then you can also say then okay and then you can do something with that value or you return a new value or you do another future within that then okay so this is basically the concept of a future chaining so let's close example three and let's go to example four Dart in here okay now in example four we're going to start talking about streams and this is this is where things get scary for some people because streamings are like a chain it's like a chain of events so whereas I like to actually show these things using comments so this is a future it works and then it produces a value and then it stops okay so let's say this is one second one second so uh the future starts in the future okay it starts it waits for one second for instance and it produces a value and then it stops however a stream looks like this it starts then it can wait perhaps one second and then it can produce a value let's go here and we say produce a value then it can wait another second and produce a value and then Can Wait Another Second produce a value and then what it can do also is to say okay I wait one second and I will produce three values okay so you get the idea it's just like a mix and match bag of candies whereas a future has a start a perhaps a delay and a value a stream has a start and a stop at the end and it has anything in between that is a mix and match of weighting and values waiting and values all right so let's put a main function in here and have a look at how we can demonstrate streams and let's go to oops we got a future int because we didn't wait on it in the previous example so let's go to previous example in here and say await I think we forgot the weight keyword in here okay so async and then we say we're now waiting for example four good so let's create a some functions that return streams okay so if you create a function that returns a stream it's kind of like future but it can produce many values and let's say get numbers okay and now in order to make sure that you can return a stream I mean there are different ways of creating streams just like there are different ways of creating Futures like if you remember from example one there are so many different ways of creating functions that return Futures it's the same is true for streams one way is to mark your function as an async function like this with a star okay so what we could do then is to say okay this function is an async function so internally you can use the um it can use the sorry the await keyword so let's say for VAR I there we go and you can see we're saying that okay go from 0 to 9 inclusive and increment I and then every time you do that wait one second okay wait one second and then use a yield keyword in order to return a value within the string so this I value will then be printed it will sorry not printed it will be injected into the Stream So this stream will look like this start uh one second delay delay and then it will produce the value of zero and then it will be and it will then be here one sec delay and it will produce a value of one once I delay two once I add until you get to nine okay so this is how this function will look like all right so this yield will insert this given value within the stream and that's how this 0 1 2 are being inserted into this returning stream okay I'm going to remove that command then we'll create another function and we can in inside this second function basically throw an exception just like we throw an exception in Futures and see how that looks like so I'm gonna just copy paste the code for that function because it is very similar to this function except that we're going to throw an exception you can see it says gets names it's async within with an asterisk and in here we can await on a future for instance but we're not going to consume its value and then we're going to yield the value of John let's just change this to a single code as well because that's uh that is encouraged to use single codes and then if you have another yield after this throw you can see in here then we get debt code because Dart understands that after throwing is an exception inside the stream then another yield will not basically yield any value we'll never even get here the throw exception will just stop the execution of this function and throw an exception down this stream okay but how do we consume these streams so the key to that is using the keyword await for okay just like you have an array let's say let's say list of string and we say names okay and then this could just give us some names you would say find a four value in get in in names like this final like this so we say actually names there we go so as we have the four there's another way of doing this exact four how do you say Loop but for streams and the way to do that is to say wait for okay and it says okay but you're waiting for a function that doesn't return a stream so let's just change that to get numbers and you can see in here we then get some number okay and then you can print it to the console if you want to so let's say prints that number and we can remove this function from here as well okay so if you go to uh our results you can see 0 1 2 3. and this will go on and on until we reach the value of nine inclusive of nine and then it will just finish there we go okay so that's that and then also you can use the same await for in order to await for the result of this get names function but since this throws an exception then you can put it inside try and catch so let's say try and then we say catch an exception here any exception and then we print that exception and then you can say await for final name in get names and then we can print that name to the console so the result will be basically this gets numbers function first doing its work because there's one second delay between every value so we have to wait about 10 seconds in here actually 9 seconds because there's 10 values and like the first one we don't I think the first one we actually have to wait for as well yeah so there's 10 delays and then you can see we get the value of John because that was a string that was produced here but right after John we throw an exception and that that exception is caught using this try and catch okay so a weight four is the same thing as a modern Loop like four final something in something but you have to put the weight in here to consume this this stream okay you cannot use a weight 4 on a on a future a wait for as its name indicates it has this four in it which is for a loop a loop is for multiple values not just one value okay or I mean it can be one value but you can't do this for futures basically all right I think we're done with this example so let's just close example four in here and then we create example five example five Dart our main function and let's go and say we have example five okay oops did I just close it yep I think I close it actually so all right let's go to example five now we're going to talk about async expand and it's a function on streams that for every value that a stream produces you can create another stream that is amazing because it is similar I think to this function then that when we had a future you could produce another feature inside this then function and async expand is similar to that what happened to our example five I think I just close it async X-Men is similar to that simply because it allows us to get a stream and for every value that that stream produces we produce another stream so every value can then Branch out into its own stream okay and this is where things get a little bit complicated because you have one screen that can produce multiple Valves and any one of those values can then Branch out into many other values okay so how do we deal with that let's let's have an have a look at an example I'm just going to dump two functions in here okay and these don't contribute really so much to this uh to what we're trying I mean they do contribute but I just dump them in here because they're functions that don't contribute to us learning about async expand all right anything that has to do with us learning A New Concept we're going to type by hand and anything that is just like a helper function then I I'm just gonna try to copy and paste it so let's see what happened in here we have a function called get names it's an async function with an asterisk meaning that it produces a stream and the reason we have this actually it doesn't necessarily mean it produces a stream it simply means that you can usually yield the keyword within this function so if you remove this you can't use yield anymore even if you say this is an async function then you can use a weight but you can't use yield in order to be able to use a weight and yield then you have to mark this as async with an asterisk okay so we have a function weights 200 milliseconds produces value of John let's just put this in single coats and then we and it weights 200 more milliseconds and then wait and produces the value of dough okay then we have a function here that produces a stream of string what it does is that it says okay I will get every character from any given string and I will produce that character as a at its own string so if you feed this guy with the value of hello then what you will get is a stream let's see is a stream that starts it will wait 300 milliseconds like this weight and then it will produce H then it will wait 300 more milliseconds and it will produce e you get the point okay so any string that you provided it will just wait 300 milliseconds before providing the um in one of the characters from that string until it hits them and you can see that we're going to basically mix these two functions so we're going to call the get characters function with the value that is produced by get names how do we do that let's go in here and Mark our function as async so let's say we have get names we call it all right but we want to say that every time this this guy produces a string and it produce a string twice one is John the other one is do we want to grab every character from that string using this get characters function okay and then we say async expand all right and then we get the event so we say name and then we say in here we produce get characters with that name all right so we say final result is and now you can see result is a stream of string what happens is every time this one says so this says John then this drum will be produced here then we'll be past the get characters then get character says okay I'm gonna wait 300 milliseconds and produce J okay now I'm going to wait 300 meters because I'm produce o and then H and then n all right and then when when that is done then this guy is going to produce dough and then do is going to be uh producing d o e from this function so the result is going to be a string that looks like this J and then o h n and then d o e with how much weight in between this one produces 200 milliseconds weight before producing John completely so 200 milliseconds uh delay first to produce this whole thing as the first string that is passed into this function and then when we hit this function we have 300 milliseconds before producing any of these characters so then we get uh 300 mil delay and then 300 mil delay here and then 300 you get the idea and then here 300 mil delay here as well then uh John before n as well and then before producing dough then we get 200 milliseconds delay delay and then before producing the D we we have 300 I think you get the idea right so now that we have that how do we await for the results of this so we can say await for as we did in the previous example final character in this whole thing okay and then we can print the character to the console let's see if we can put some commas in here to get the formatting a little bit better and then we can look at their results and see what happens oops oops there we go and let's run the application you see there we go right so John stop and then though good so async expand will basically allow you to produce a stream for a stream okay let's go to example six we say example six in here if I can spell it main function usually this function is an async function let's just mark it as async and then we go to our FS watch as well and we say we're running example six in here so we've seen how uh async expand works but there is another function on streams which I think is very useful it's called reduce and what this reduce really does it is that it gives you the current uh and the previous values of a stream and it will allow you to do some calculations on it so let me put a stream in here which is a very simple stream and we're just going to copy paste it because it doesn't again contribute to reduce and you can see it says get all ages and it just produced 10 20 30 40 and 50 all right so what you could do is to say okay let's say you want to sum this up you want to sum you want to get the sum of all these um ages how do you do that well we know a weight four so let's say int and sum is zero okay then we say await for final age in all ages and then we get the uh gets the age from this function and then add it to the sum and then we can say print sum okay and then you can see the value is immediately printed to the console okay so that's one way of doing it however you can also use a reduce function and let's say that we have a function in here we say int add and it takes a and b and it returns a plus b then we could go in here and say well final sum is equal to get all ages and then you can say reduce and then your Pat you pass your function to it you could either pass your function to it or you could say a b and it's a plus b here as well you could do that too but you could also Define your function separately and this works a lot nicer in languages like rust and Swift because you could literally say reduce and then if you say plus because plus is an operator that takes left hand side and right hand side but start doesn't keep up with Swift and rust it is cleanliness I would say so a you can't pass a uh you can't pass an operator like this to another function unfortunately hopefully Dart will update its syntax to be more modern I would say but for now we have to Define separate functions that do exactly the same thing as an operator does so you should be able to pass it here but you can't all right so let's put add in here like this and you can then you can see the result of this is going to be a stream of actually it's a future events right because reduced returns a future okay so we can then await on it so we say wait on the result so we resolve it to an integer and then we can print it so we say sum of all numbers is and then we say dollar sum there we go and then we get some wall numbers is 150 okay so reduce will resolve the current value and the previous value of a stream in this case it will give you 10 and 20 and then you say okay the result is 30. then it will take 30 and it says okay 30 plus 30 60 60 plus 40 100 100 100 plus 50 150 okay so it just accumulates the values two at a time so he says I'll give you these two you give me a value then I'll take that value and give you the next value and then you produce a new value I'll take the new value with the next value you get the idea right okay that's example six let's go to example seven and we do the usual dance example seven main function usually is an async function let's do that usually I mean in this particular chapter example seven there we go so let's now talk about asynchronous generators and this is something that we haven't talked before actually maybe we've seen asynchronous generators before but let's have a look at an example let's say that we want to have a function that takes a start integer and an end integer and it will simply um it will simply go from that start to that end value and it will call a function with that value to know whether that value should be included in the resulting stream and then we're going to pass separate function pointers to that function it's a little bit abstract to explain it to like this I think it's a lot easier if you have a look at the actual implementation so let's say we have a string and it's a it's a stream of integer we call it numbers okay numbers like this and we say okay give us three name parameters and here we say int we say we go from start as default zero then we say int and is let's say four okay and then we say okay we want a Boolean function in here like like this and we pass our value to it and it has to tell us whether it should be included or not so we say included and then we have a Boolean function in here let's put this inside is type definition so we say type Def is included is equal to this Boolean function and then in here we say is included included like this and we say it's a function all right so our job is now to produce a string let's say that we're an async function as well so that we can yield values okay and then we go through this there we go so we go from I uh sorry if we go from start and um lesson or actually let's say less than and we don't want to include n and then we increment I and then we say if function is null or the function the result of this function is true then we yield this value all right so you have to if you don't pass a function to us we will yield this value anyways if you do pass a function to us we will call it like this all right and uh if the return value of this function then is true then we will yield I think there's actually a better way of doing this maybe like this F question mark dot call and then we say I is equal to true I think you could do this as well but maybe it's a little bit more abstract to do it that way so we first can say if it's not or if we call it and it returns true then we yield the value okay so that's our numbers function then we can go ahead and have two functions that say that they filter out even numbers and odd numbers so you can see this one produces even numbers only given an integer it will give you a true value if that number is divisible by 2. and the other function does the opposite by making sure it's not divisible by two meaning that it will yield not only or it will return true for only um odd numbers okay so what we're going to do is then to go ahead and say await and we say await for final value in numbers like this and then we'll say print print values or sorry print value so in the first example we'll just get what are we going to get 0 to 3 and 4 is not included then we can go and say okay this time around we want to wait for let me just dump some coding here so we say go and call this numbers function and end at 10 start at 0 by default all right let's put a comma in here as well and then we say go from 0 to 10 exclusive and then as the function get only the even numbers okay and you can see then the result is going to be 0 2 4 6 8. and if you do some induce the same thing but only for odd numbers here we go like this and we say odd numbers only like this then we will get one three five seven and nine okay so this is this is the point of an asynchronous generator uh that is created like this with an async and then a yield you can literally just blend in another function inside and then dependent on the result of this function then you can either yield or not yield a value okay so this was this example is just four demonstrating how you can use an asynchronous generator with streams and a function pointer okay so example seven is done let's go to example eight uh Dart filing here say the main function and let's make it an async function then we change our FS watch as well to example eight good so now let's talk about example eight um so in and we've talked about asynchronous generators using this async syntax like this and then returning it stream but you can also use these a a keyword called yield and then sorry yield with an asterisk how does that work so let me bring in two functions and we say these two functions one returns male names a stream of male names and it's an asynchronous generator and you can see we're just yielding three names and then female names how about we go ahead and create a stream now and someone tells you okay given these male names and female names how can you return all these values inside a new function and you say all names okay so how do we do that then using what we've learned so far you could say well this is a stream I'm just going to say await for so let's say a weight for final male name in male names like this and then you could say um yield and then you can save mail name like this but you know that in order to use these uh actually this is async 4 and loop can only be used in async function they say okay I'm going to change this on async function so this is fixed now then you say ah in order to use yield I've learned to change this into an async asterisk good so now you have that then let's just copy paste that and say female name and then we go through female names all right and then we yield that that female name like this however there is an easy way of doing that and that is if you just remove your Loops like this like this remove it there as well and then just change this to yield like this and then call these functions let's say like this the function menu Isn't defined I thought male names there we go female names like this did we say female name in the previous example let's see what what I did male names female names female name okay this is fine so you can then use the yield asterisk function in order to create so this is your Stream So what it does and what DART does it says okay you're creating a stream I start from here then I will go and say put John in here John and then Peter and then Paul and Mary Jane and Sue like this okay so this is this will be the result of this stream it will literally take the first streams resolved and places in your stream and then the next stream in that order okay so that's how yield when an asterisk works let's go to example nine example nine dot Dart in here we create a main function and then we're gonna talk about stream controllers and stream controllers and I mean if you've seen now streams and you you have seen streams you can see that the function at the functionality to create or the code to create streams is a little bit abstract in that you have to think about something that maybe starts in the in the future produces some values or exceptions and then ends in the future so it's a little bit like an abstract thing actually to talk about however stream controllers make the creation of streams a little bit less abstract in that if they wrap them inside an object that you can control in real life or in real time rather so let's say we create a controller we say controller is a stream controller controller and it's going to be Auto imported I think from Dart async so make sure that if your editor is not Auto importing this that you import it yourself Dart async and then we say okay we're assume controller of string okay and then we say controller dot sync dot add and we say hello and the sink is where you literally sync your values in it you literally put your values inside the sink okay just imagine async where you wash your hands that kind of sink you put your values in there okay hello world and then you can treat this controller as a stream so you say wait for final name or value in stream sorry at controller then you have a stream in it then you can print that value and then at the end you say controller Dot close all right like this and if you look at the results then you get hopefully hello world I'm not sure oh by the way in the previous example now I'm thinking about it example eight I think we didn't actually consume these values so let's just say consume these because I can see no values being printed because we're still on example eight let's say a weight for final name in all names and then we print those names there we go and then we can close example eight okay and then let's change our FS watch as well to execute example nine like this and we go and you can see hello world is being printed to the console okay so that's how you can use a stream controller I mean there's other examples of using stream controllers of course but this is just like the simplest example I can show you so a stream controller is that is a an object that you can add values to and you can also read values from so it acts in two different ways it's like read and write whereas a string is a read-only a stream controller is read and write okay so example nine now let's create example 10 in here and then we say we have a main function that is probably an async function and then we change this to example 10 NFS watch as well and then we close our terminal for now okay now let's talk a little bit about stream Transformers now a string Transformer is a some sort of a class that takes one stream and it changes it to another stream okay so let me just show you an example let's have a function that produces a list of names okay and this is something that we haven't seen before this particular way of creating a string and you can see you can create a stream from an eye dribble and you pass it and I triple and every element inside that iterable will will then be placed inside your stream okay so in order to consume the stream and let let's say someone tells you consume every value in the Stream and convert it to an uppercase value okay operate case value then you say okay I've learned that say a weight for final and name in names and then you say print name print name.oper case Okay so this is one way of doing it and then you can see all those names will be printed to the console in uppercase but there's another way you could say take names and then map every value and say events to operate case okay and we could just change this to the value of name as well so this is another way of doing it and then you can then consume name and you can see it prints the exact same thing so it converts every value to operate case Okay however if this is something you're doing a lot in your program in your application you don't want to map your streams every time you want to convert them to an opera case stream with values as Opera case so you could create a um you could create something called a stream Transformer as its name indicates it takes the stream and transforms it to perhaps another value of the same type or another value of a different type so in order to do that let's say that we want to create a stream Transformer that takes a stream of string and converts every element to an uppercase value okay so let's say that we create we call a class we call it two uppercase and we extend stream Transformer base okay this guy takes two values and inputs add an output since we are going to work on an input substring and output a string then we're just going to say we're transforming a stream that is a string and then you have to implement this bind function in here okay and you can see you get a stream of string because in here we said string of string or at least we set string and it understands the input as a stream of string and then it understands that here we also set string meaning that the output also has to be a string okay so you have to implement this bind function and you get a stream as its input and you have to produce an output and you can see we're taking the input and then we're doing the exact same functionality using map which we did up here but we're just returning that news stream from this function so now you have a stream Transformer that you can go ahead and use so this is again getting a little bit more advanced I completely understand this but we also have some Advanced people watching these videos so we have to ensure that we're catering to both beginners or actually the beginners intermediate and advanced uh people watching videos so then we can combine this concept with extensions and there is a separate chapter of the dart crash course dedicated to extensions if you haven't watched that please go ahead and do that now because it's going to be very useful for you let's say we create an extension and we say we're creating our extension on streams of string and let's say that in here we want to create a getter and we call it a capitalized let's say we return a stream of string and we call it a get capitalized and what this guy returns is that it calls at this which is a stream and it says transform it using which Transformer or instance of this guy boom like that and since this is not a necessary keyword we can just remove it and the result will just look like this okay and you can do the same thing you can create another getter in here that doesn't even use a Transformer instead just uses map directly so let's say string of string in here and we say gets capitalized using map and then we just use map directly in here okay boom boom let's see we have one missing uh parenthesis somewhere here okay so you can see this one uses a Transformer this one just uses map directly so we can go and consume these values so I'm just going to take some code and copy and paste some code and dump it up here like this like this so in the first example we're going through names and actually let's see yet this is a getter or it's a variable it's not a function okay so then we're saying that capitalized you can see it returns a stream of string and the next one just capitalize using map and both are going to return the same values so there we go let me clear the console Set uh Kathy and or Kathy and Lars and the same thing is going to be printed to the console I have a little bit difficulty saying Lars because I think it's a German name large Lars Lars I don't know Lars something between s and Z maybe okay but that's not the point of this example so you can see how we're using uh stream Transformers in this example tab let's move to example 11 then oops there we go this is this is something that happens that happens to me every chapter or not it doesn't happen to me I do it every chapter pretty much I minimize I do command M for minimizing instead of command n for creating a new file example 11 Dart okay and a main function which is probably going to be an async function as well and let's go and do our FS watch correctly in here like this okay so what we're going to do in this example is going to create a a future or actually yeah a future out of a stream using a function on streams called to list so I'm going to bring a stream in here and you can see it's called gets names and just has three values within that Stream So if we go and if you want to basically grab all these names but as a list all right how do we do that how do we say get the list of all these values well if you have a look at get names and call it and then get the stream out of this there is a function on this called to list you can see that it then returns a future of the list of strings in order to consume that feature you can say a weight on it so you can say final all names then you will get a list of string in here okay then you can print that you can say print all names like this and then you get the result printed to the console so you can then say four final name in all names like this and you can say print name or you could have in uh in I mean if we didn't talk about two lists you could have said a wait for get names and then you print the names okay but I just want to show you how to list works as well remember to list this function when you await on it it you have you're basically waiting for this entire stream to finish okay remember that so if the screen take 20 seconds to complete your code in the main function is going to wait 20 seconds before it before it proceeds to line number three okay so two list waits for this entire function to produce its entire stream okay example 11 done and let's create example 12 like this okay and then we're gonna go and actually example 12 is a little bit longer than other examples so let's grab a cup of tea or coffee before continuing perhaps so async function and then we go and Fs watch example 12 as well in this example we're gonna handle errors in our streams so let's just create a simple stream and we're going to call it get names and you can see where this is John Jane and then all out of names it just throws a string okay so in this example I'm going to show you three different ways of handling errors inside a stream so one way is using handle error function a function on stream so if you call a function like this that produces the streams and then you can say handle error okay the result of handle error is a new stream that basically will allow you to handle errors in the original stream which is this get names function for instance so let's create an extension so we're gonna go here and we say we have an extension at T on stream of t of any screen basically and let's just call this extension perhaps absorb errors like like this and then we have a function in here that Returns the same exact stream and then we say it's called absorb errors using a handle error and then this function what it does is internally calls handle error as you can see in here and it completely ignores the error and the stack Trace like this and it just doesn't do anything okay like this and we can do it like that so it's actually no let's put the comma in there so then what we'll do we'll go inside our main function and then we'll start using that uh absorbers uh using error Handler so I'm going to dump some code in here you can see we're waiting for name and get names and then we say dot absorb errors using error hand sorry using handle error and then you can see the result we'll get John Jane and then the error is nowhere to be found so the error was completely absorbed using handle error okay there's another way of doing exactly the same thing is using error handlers so let's create another uh getter in here or another function we say string T and we say absorb errors using handlers like this and the result of this is going to be that we are going to transform the current stream we're saying transform transform but we don't have to create a new Transformer class and in here we just say we create a stream uh oops Transformer Transformer it's it's a mouthful and then we say we create a stream Transformer from handlers did I create it stream Transformer and we say from handlers okay and from handlers we say in here we have a function call sorry a parameter handle error like this and this guy just takes some parameters in here and I think the last parameter is sync and in here we just say well a sync.close like this so this is the action we're taking upon um this stream airing out so you can create a stream Transformer and pass it to a transform function in order to absorb your errors as well so then we can go ahead and consume the result of this stream as well like this you can see John Jane and John Jane again printed to the console so these both functions are behaving exactly similar to each other then I'll show you another example of of absorbing errors inside a stream and that is using an actual Transformer okay so we say we create a stream error absorber and it extends stream Transformer and let's say this is a generic class of T and it takes T and returns to so any stream will be returned exactly as it is okay then we'll override our bind function in here okay then what you can do is just to uh this is one way of doing it of course but I'm going to show you another way let's go in here in the bind function then we say we create a controller controller in the Stream controller of the exact same type that we're consuming and returning if we return our controller as a stream okay because the result should be a stream then we say in here string listen so start consuming the values of that stream like this and we say Okay upon getting new values you see it says on data is the first parameter then we say controller dot sync.ad call this function so literally add take that value that is coming inside the stream and add it to the sync of our controller then when an error happens just ignore that error like this and then when we're done consuming this stream then say controller Dot close call that close function all right like this so this is the third way let's see what it's saying saying missing concrete implementation on screen transfer cast try implementing stream Transformer stream absorber uh I don't think actually Transformer oh we said transform we should say Transformer base okay now that we have this Transformer let's go ahead and create a inside our extension a usage for it like here you can see there we go like this so you can see we have a stream of T absorb errors using Transformer and it transforms the current stream using our instance of stream error absorber Transformer in here okay then we can go ahead and call that function so let's go ahead and call it like this we have sore of Errors using transforma you can see the result is exactly the same slate says John Jane John Jane Johnjay okay so three ways to absorb errors inside a stream okay now with example 12 let's create example 13 example 13. Dart main function let's turn it into an async function usually and then change our FS watch as well to say example 13 and then we can get rid of our terminal as well okay now in this example we're going to have a look at stream at transforming it using async map and also we're going to use the fold function on the result of that async map so what async map on a stream allows you to do is to transform every element of a stream into its own future okay so let's say for every element produced by a stream you want to do some work that may be taking some time okay so such as calling an API for instance okay so let me produce a streaming here and place it right here okay and then we'll have a function a helper function that will just dump here you can see it's called a future that returns a list of string and it's called extract characters okay then it will create a list of strings so a string for every character within the string it weights 100 milliseconds before producing a new value and then it goes to the result of this function and then adds every character to it so if I pass John to this function the return will be a feature that has the value of J then o h n like this okay so this is actually a really good example I get how copilot could understand that okay so this is what this function produces a future of a list of strings so it produces this if you pass John produces this if you pass Jane and this if you pass gel all right so now that we have these two helper functions we can go ahead and have a look at our actual example so what I'm going to do is to say final actually not final and let's just start with get names and this get names and you can see it is a stream of stream let's say for every string that this produces we want to call this function and grab its value okay so then you could say that async map and you can see it says you return a future within this and then we say okay we get the name and then for that we call extract characters of that name and then if you put this inside a value let's say result then you can see your result is a stream of a list of string okay because f for every value of a string that this produces then you producing a list of string so and a list of sorry a stream of string will be a stream of lists of string okay and then now that we have that we can go ahead and say okay then we want to fold this stream and then we say okay we give you an initial value of an empty string like this and then you give us this um uh the previous value which is the previous value is going to be our string for us and this element you can see it's going to be the list of string then we're going to say okay then we take the previous value and then we perhaps actually we could create a function in here let's just create a function then we say the element we will join it so the list of string will join it using a space so we say final elements and then we'll return the previous value and the elements like this and a space at the end all right so our result then let's see it will be a future string and then we can await on it and it will be a string then we can print it to the console so print result all right so let's see what the result is going to look like John Jane and Jill there we go right so that's that's how basically async async map unfold work so fold will allow you to it's kind of like it one other example that we saw before it's kind of like reducing kind of okay so it takes a previous value with an initial value and the new value and then you do some functionality and you return a value and the stream will then be the stream of that return that you're returning from this function so that's example 13. let's go to example 14 Dart and then the main function and async like this and let's just change our FS watch to example 14 as well now in example 14 we're going to have a look at um another example of async map all right um so we're going to async map which converts every element of our stream to a stream of itself all right and we've already seen this async map before by just wanted to show you another example of how to use it so let's have another streaming here and we call it gets names then what we're going to do is to for create a function that takes a string value and then it will repeat it three times so we say we say a stream of string and we say times three and it's a string value and then we say string from I trouble okay like this and let's bring it to the next line and in this itable we say iterable generate three times and this particular value like this I think we can do like this boom boom all right so now we have a string that sorry a stream that repeats the given value three times like that so what we could do is to go in the main function and we say that we say get names and then we say async expand and then for every name that we get in here we call times three at times three that name all right and then we say final names three times all right so what do you think the result of this going to be I mean if you had a look at this example and just like that without resolving the type of names time three time sorry names three times variable so let's have a look it is the result of calling this async function uh sorry the stream function get names and for every name it is producing a another stream which is a stream of string so if every string is becoming its own stream of strings then the result of this should be a stream of strings and if you hover your mouse over it you can see it's a stream of strings okay then you can say wait for final name in names three times and then you print those names so let's have a look there we can see Bob three times Alice three times and then Joe three times okay so this is another example of using async expound done with example 14 let's create example 15 in here main function make it async oops async and then we go into our FS watch example 15 like that and then we're gonna in this example talk about broadcast streams and this is something we haven't done before okay and I'll just quickly explain what broadcast streams are a stream is a it's an object that can be listened to from one listener at a time okay so if you have a stream a variable a stream and then you start going through that stream using a wait for uh function or a sorry and I wait for a keyword combination then you can only do it once once you consume that stream you can't do it you can't do it again okay and it actually depends I can't really say that you can't do it it depends where that stream comes from and that's where the source of the stream then divides into two types one is a broadcast stream and another one is a non-broadcast screen okay a broadcast stream is a kind of stream that multiple listeners can listen and consume at the same time whereas a non-broadcast stream is a stream that only one listener can listen at a time all right so let's go ahead and start talking about um this using stream controllers so I'm going to create a functioning here and I'm going to call it non-broadcast stream example I'm just going to dump it in here because it's something something we've done before and you can see it just creates a stream controller off string and then starts adding values to it okay and within this function you can see I mean we don't actually return it stream as you can see in here okay but within this function we're saying try and catch and then we're saying a wait for final name in controller and then we're doing another await for name in controller so while we're listening for this controller as a stream we're listening again for every element okay so it's like a loop within a loop and since this stream controller is not a broadcast stream controller as we've seen a non-broadcast stream generally cannot be listened to by more than one listener at a time however we're breaking that we're breaking that ruling here so we're listening to the stream and for every element that the stream is producing we're listening to it again so this should ideally not work right so let's go up here and test this out and let's say a weight non-broadcast stream example and then you can see in here when we run it as soon as we get the first element in here here we print that element and then as soon as we start listening to that stream one more once more is this bad State stream has already been listened to all right so to change this what we could do is to go ahead and copy this code that we've written in here like this oops like this and then I'll paste it in here and then let's just change this so we say late final controller and say this is a stream controller uh controller off string like this okay and then in here we could say controller is a stream controller uh offstream and then we say it's a broadcast stream controller as you can see in here okay and let's just change the name to broadcast stream example and now that you have a broadcast uh controller what we're going to do is to say okay we create subscriptions to it uh let's actually we need to change quite a lot of code from here so I'm just going to remove all that so we have a stream controller that's a broadcast stream controller and then we say final sub one which is a subscription and we say controller that's stream Dot listen all right and we say subscription one got the new name and we create another subscription in here like this sub 2 and then we change this print statement to sub 2 as well then we go and grab these controller sync add lines of code and then we say controller Dot close like this all right then we say controller uh on cancel when this controller is canceled then we also need to get rid of our subscriptions so we say sub one dot cancel like this and then we say sub 2. cancel and we just print we say on cancel something like this all right so let's then call this function from here we say await broadcast stream example uh like broadcast stream example oopsie Daisy like so many keys being printed sorry so many keys are being uh press in here so let's have a look at what happened so the first one which is a non-broadcast stream example just airs out and the second one just says the subscription one got the name of Bob so it is subscription two then we got Alice and then Joe and then got canceled that's it so you can see in this example we had basically a stream controller that could be listened to its stream could be listened to more than once and that is thanks to creating a broadcast stream controller okay so this is how you can create a broadcast stream controller in this example let's go to the final example of this chapter which is example 16 and create a main function with an async suffix and then we say watch example 16 as well like this and then in this example we're going to have a look at a something that I use usually in projects and actually not usually in some in some projects I've used this extension or this functionality and it is a little bit Advanced I would say so don't get scared but what this example does is that let's say that you have a stream and that produces some values let's say a stream that for instance produces names okay but the stream produces one name and then Waits a number of seconds and then produces another name with another number of seconds or maybe milliseconds but what you want from the any stream that you produce for instance in this example is to for them to produce one value at least at least one value per for instance one second however if they go over one second before producing the next value then you want to kind of say time out okay so you want a stream that is timely it works in a timely fashion you want to say you have to produce one value every X number of seconds for instance okay and this is what we're gonna achieve with with this example so let's create some sort of a strain Transformer that errors out if the given stream if the input stream doesn't produce a value within a given number of seconds okay so let's go in here and I think we've already fixed FS watch uh have we yeah all right so let's go and create a stream Transformer let's say we call it maybe timeout between events or something like that class timeout between events and a stream Transformer that works on an element of any type in here we say expense stream Transformer Bass of inputs of an output of the same type okay then what we need to do is to create the bind function oops a string Transformer base I think we need to import Dart async and then we say bind in here okay so we take a stream of e and then we produce a stream of v as well in here so we need a few um we need a few variables in here so let's create a first sorry first create a stream controller of that same stream type and we say this is optional and then we say we also have a stream subscription and then we create that stream subscription so let's say stream subscription okay it's optional as well and then we create a little timer and we say timer as well okay and you see a lot of you have asked me which extension Visual Studio code allows you to see all these warnings right in line and this is called error lens it's an extension called air lens I mean it's great unless you get to these functions where you haven't really done the scaffolding of your function completely and then you get errors everywhere like they're so so invasive they're like in your face so I think in these cases Airlines isn't really helping so much it's just making me very stressed okay so let's create our controller so we say our control is actually equal to a stream controller okay and then a stream controller in its Constructor you have a few parameters that you can pass one is on listen Okay and we say unlisten is a functioning here like this and then we have another parameter in here expected to find really on listen oops unless and let's just remove that and then we also have on cancel so we say on cancel when we cancel this uh controller let's cancel the subscription and the timer all right so we have that in place then we can go ahead and say just return the controllers stream controller dot stream like this all right okay so we have the Scaffolding in place so what do we do on listen so let's unlist and actually start listening to the input stream so we say in here we say subscription is equal to the stream start listening to it like this and then we get data here data like that okay and then within this let's see if I can put a comma all right so now every time we get data we need to cancel our timer because this timer is kind of like the expiration timer so every time we get data we kick start it again okay because then it weights X number of seconds before the next item is produced and then it will time out okay then we say okay when we get data just cancel the timer because we know that uh yeah basically we got data we shouldn't time out then we say okay as soon as we do this we create a new timer and let's say timer dot periodic like like here and we say the duration is a uh is a value that someone has to pass to us so let's say in here we say final duration is a duration like a parameter and we create a Constructor in here and we say it's a const Constructor and we make this a required named parameter like this so now that we have the duration we can use it in here let's say the duration like that like this okay so when we get that um timer when we create the timer in here we could say timer at as soon as that is kicked when the timer basically kicks and you event we want to throw an exception so let's go ahead and Define that exception in here okay I'm gonna dump some values in here so an exception timeout between events exception then as soon as the timer it kicks a value then let's just say we want to add that exception to our controller so we say controller dot add error okay and in this add error we just say oopsie Daisy like this we say timeout between events exception and then we just say timeout like this boom all right and then after we have that uh we have the subscription on lesson we also have to add a other actually wait a minute and this is when the timer kicks and it ends in here then right after this we need to also ensure that our controller gets the data so we say controller dot add data okay so we add the data but we also set up a new timer to kick off after duration and then if that timer kicks and you value in then we will get an exception in our stream okay so we have unless unless and let's also Implement on cancel uh um don't we have on cancel after our own lesson let's see where on lesson ends I think it's here and then we say on error what else do we have on error cancel on air we have quite a lot of these values seems like it and but I believe you also have to have on cancel and let me see on cancel like this and the name parameter on cancel isn't to find try correcting the name so let me just remove this and see what is happening so we have a stream controller and we have on listen let's go in here and on resume and I can see we have on cancel in here for sure but maybe I'm just oh here we've already implemented on a cancel I was just implementing at the wrong place but I think we have on cancel already okay so that is already set up now so now that we have our let me actually make sure that we've done it correctly subscription timer yeah seems fine so what we need to do then is to go ahead and implement the other parameters to this function you can see here we have a controller stream controller and then subscription stream Dot listen and then we have the data coming in here okay but we also have other parameters I believe uh which are which should be implemented in here and this is for instance on air uh like this and we say if you get an error then call the controller add error like that and also we have undone and we should say controller Dot close like this and again if this is all making your head spin it's just fine I mean it that's that's what running a little bit more advanced code is like sometimes it is a little bit more difficult to grasp the concepts but I think you need to go through the code yourself it's not so much code it's just I mean if you if you imagine if we had zoom level if I went in here and said zoom level one which the default one this code is very little it's just this okay so it's shouldn't be that scary to look at and there's lots of commas in here I mean if you remove the commas of code it'll be even shorter okay so just because it looks big it doesn't necessarily mean it is too complicated so don't worry about it if if you don't understand it right now just know that we have a timer that's the core of this functionality the timer that kicks in every time or we create a timer every time we get data okay so when we get data we create a timer that kicks basically it starts the timer or it doesn't start actually it it elapses that timer elapses after this duration and every time we produce data meaning that let's say that you have a value produced here and the duration that we provide to this class is one seconds but your stream Waits two seconds okay then your timer is going to kick here right here it's going to be the timer it's like oops one second elapse but you're waiting two seconds and when that happens then we're going to throw an exception right in the controller meaning that the entire stream is going to stop okay so then it's going to be canceled and your subscription gets canceled and your timer gets canceled and your interest room's got to throw an error okay so if you look at the code it's very simple the entire core of it is this timer okay so let's create a little extension on stream and which can use our uh Transformer so I'm going to place it here boom boom you can see there's an extension on stream and you can remove this name if you don't want it oops actually says the Declaration with isn't reference okay it's fine so we have this extension which you can see is transforming the given string and is using our Transformer with a given duration let's put some commas in here to get a formatting a little bit better then we can go inside our main function and I'm going to dump some code in here as well like this all right and we have gets names I think we actually didn't implement the gets names function I'm going to dump some code in here for get names as well and you can see it's an async function that Returns the stream John Jane Doe all right and it produces John and it waits one second and then for this is Jane but then it waits 10 seconds before produces producing dough and what we want is to go ahead in here and you can see we're saying get names but put a timeout of three seconds so if it if this stream Waits three seconds between producing its next element then we want to get an exception and then we'll get this exception in here so if you run our application he can say it says John Jane and then as soon as three seconds pass then we get an exception in here okay this is there's a timeout so this is this example and was the last example in this chapter I hope that I wasn't ranting too much I really did try to speak as fast as possible without making it uh um too difficult to understand uh so but I completely am aware of that this chapter is a lot more advanced than other chapters but that's the nature of asynchronous programming for me it becomes it has become second nature but I completely understand also for some people it could be difficult to grasp if you have any questions about this chapter for instance particularly just join the Discord server the link to which is in the description of this video is also in the description of the dart crash course playlist so join the Discord server and ask your questions there if I or someone else in the Discord server can be of help I hope you enjoyed this chapter and see you in the next one
Info
Channel: Vandad Nahavandipoor
Views: 16,760
Rating: undefined out of 5
Keywords:
Id: -zNC2hWftho
Channel Id: undefined
Length: 88min 22sec (5302 seconds)
Published: Mon Dec 26 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.