Skip to content

Commit

Permalink
Fixes broken link in async reading
Browse files Browse the repository at this point in the history
  • Loading branch information
nickbradley committed Dec 19, 2024
1 parent f39cf51 commit 9cf5439
Showing 1 changed file with 39 additions and 41 deletions.
80 changes: 39 additions & 41 deletions reader/content/construction/async/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ weight: 2

{{< youtube T__CJfXswbA >}}


Over the past decade, advances in computers have happened through increasing the number of cores within a processor rather than raw clock speed. To take advantage of this, most modern programming languages support some model concurrent execution. While at its core the code you write in JavaScript (and by extension TypeScript) can only execute in one thread a thread pool does exist in both Node and the browser to ensure that long-running tasks can be offloaded in a way that does not block the main thread. The model supported by JavaScript is that of asynchronous execution.

<!---
Expand All @@ -28,17 +27,16 @@ TODO: EXAMPLE
The [Async Cookbook](https://github.com/ubccpsc/310/blob/main/resources/readings/cookbooks/async.md) contains many code-forward examples demonstrating how to call and test asynchronous methods using callbacks, promises, and async/await.
{{% /notice %}}

## Callbacks
## Callbacks

{{< youtube ZyiLFip7nqk >}}


### Shortcomings

Two common problems manifest with callbacks in practice. First, handling errors is difficult because callbacks are invoked, but they do not _return_ a value. This means any information about the execution of the function making the callback must take place in the parameters. Node-based JavaScript addresses this with the [error-first](http://fredkschott.com/post/2014/03/understanding-error-first-callbacks-in-node-js/) idiom. For example:

```javascript
fs.readFile('/cpsc310.csv', function(err, data) {
fs.readFile("/cpsc310.csv", function (err, data) {
if (err) {
// handle
return;
Expand All @@ -57,17 +55,17 @@ fs.readdir(source, function (err, files) {
// handle
} else {
files.forEach(function (name, index) {
fs.stat(files[index], function(err, data) {
fs.stat(files[index], function (err, data) {
if (err) {
// handle
} else {
if (data.isFile()) {
fs.readFile(files[index], function(err, data) {
if (err) {
// handle
} else {
// process data
}
fs.readFile(files[index], function (err, data) {
if (err) {
// handle
} else {
// process data
}
});
}
}
Expand All @@ -90,77 +88,77 @@ Although promises do enable try/catch to work properly, they do not provide any

```typescript
var file = null;
fs.readdir(source).then(function(files) {
fs.readdir(source)
.then(function (files) {
file = files[0];
return fs.stat(file);
}).then(function(fileStat) {
if (fileStat.isFile())
return fs.readFile(file);
}).then(function(fileData) {
})
.then(function (fileStat) {
if (fileStat.isFile()) return fs.readFile(file);
})
.then(function (fileData) {
// process data
}).catch(function(err) {
})
.catch(function (err) {
// handle errors
});
});
```

Promises can only have three states, _pending_ before it is done its task, _fulfilled_ if the task has completed successfully, and _rejected_ if the task has completed erroneously. Promises can only transition to _fulfilled_ or _rejected_ once and cannot change between _fulfilled_ and _rejected_; this process is called _settling_. [HTML5Rocks](http://www.html5rocks.com/en/tutorials/es6/promises/) has an extremely thorough walkthrough of promises where you can see how many of its features are used in practice.

[//]: # (<img src="./figures/promise-states.png" width="512px" alt="promise states">)
[//]: # '<img src="./figures/promise-states.png" width="512px" alt="promise states">'

{{< figure src="promise-states.png" >}}

At their core, promises are objects with two methods `then` and `catch`. `then` is called when the promise is settled successfully while `catch` is called when the promise is settled with an error. These methods both themselves return promises enabling them to be chained as in the example above (three `then` functions called in sequence). It is important to note that there can also be multiple `catch` statements (e.g., in a 5-step flow you could catch after the first two, fix the problem, and then continue the flow while still having a final catch at the end).

One nice feature of Promises is that they can be composed; this is especially helpful when you are trying to manage multiple concurrent promise executions in parallel. This is the explicit goal of `Promise.all`:

```typescript
let processList:GroupRepoDescription[] = [];
let processList: GroupRepoDescription[] = [];
for (const toProcess of completeGroups) {
processList.push(gpc.getStats("CS310-2016Fall", toProcess.name)); // getStats is async
processList.push(gpc.getStats("CS310-2016Fall", toProcess.name)); // getStats is async
}

Promise.all(processList).then(function (provisionedRepos: GroupRepoResult[]) {
Promise.all(processList)
.then(function (provisionedRepos: GroupRepoResult[]) {
Log.info("Creation complete: " + provisionedRepos.length);
// can also iterate through the individual results
}).catch(function(err) {
Log.error("Creation failed: "+err);
});
})
.catch(function (err) {
Log.error("Creation failed: " + err);
});
```

Analogous to `Promise.all` is `Promise.race`. This allows for starting multiple async calls; `then` is called when the _first_ promise fulfills, rather than when _all_ of them fulfill as is required for `Promise.all`. `Promise.race` can be handy when there are multiple ways to accomplish a task, but you cannot know which will be fastest in advance, or if you want to show progress on a task by updating the user when data starts to become available rather than waiting for a full operation to be complete.

When working with promises it is _strongly_ encouraged that you end every `then` sequence with a `catch` even if you do not do any meaningful error handling (like we do above). This is because promises settle asynchronously and will fail silently if rejections are not caught; they will not escape to a global error handler. Another common mistake when working with promises is that `then` is not applied to the right object. In the above example if you called `then` inside the `for` loop you would not be notified when all promises are done but one-by-one as they execute. Adding verbose debug messages can really help here, so you can keep track of the order your functions and callbacks are executing.

<!--
<!--
TODO async/await
-->

## References

* Discussion of some [challenges](https://www.quora.com/What-is-the-difference-between-deadlock-and-livelock-deadlock-infinite-recursion-and-starvation/answer/Akash-Kava) with concurrent programming.
- Discussion of some [challenges](https://www.quora.com/What-is-the-difference-between-deadlock-and-livelock-deadlock-infinite-recursion-and-starvation/answer/Akash-Kava) with concurrent programming.

* [Mozilla](https://developer.mozilla.org/en/docs/Web/JavaScript/EventLoop) event loop overview.
- [Mozilla](https://developer.mozilla.org/en/docs/Web/JavaScript/EventLoop) event loop overview.

* Article about the event loop with [more examples](http://altitudelabs.com/blog/what-is-the-javascript-event-loop/).
- Article about the event loop with [more examples](http://altitudelabs.com/blog/what-is-the-javascript-event-loop/).

* Article about the event loop that includes some detail about [closures](http://blog.carbonfive.com/2013/10/27/the-javascript-event-loop-explained/).
- Article about the event loop that includes some detail about [closures](http://blog.carbonfive.com/2013/10/27/the-javascript-event-loop-explained/).

* A collection of promise use cases can be found [here](http://exploringjs.com/es6/ch_promises.html) and [further examples](https://www.promisejs.org/patterns/).
- A collection of promise use cases can be found [here](http://exploringjs.com/es6/ch_promises.html) and [further examples](https://www.promisejs.org/patterns/).

* While promises seem really fancy, [how they are implemented](http://www.mattgreer.org/articles/promises-in-wicked-detail/) is relatively straightforward (or even more [straightforward](https://www.promisejs.org/implementing/)).
- While promises seem really fancy, [how they are implemented](https://mattgreer.dev/blog/promises-in-wicked-detail/) is relatively straightforward (or even more [straightforward](https://www.promisejs.org/implementing/)).

* Sencha also has a nice [promise intro](https://www.sencha.com/blog/asynchronous-javascript-promises/).
- Sencha also has a nice [promise intro](https://www.sencha.com/blog/asynchronous-javascript-promises/).

* Callback, Promise, async/await [concrete example](https://medium.com/@gab_montes/is-async-await-a-step-back-to-javascript-95e31263dd31#.8jtvqy8fb).
- Callback, Promise, async/await [concrete example](https://medium.com/@gab_montes/is-async-await-a-step-back-to-javascript-95e31263dd31#.8jtvqy8fb).

* [Async/await](https://hackernoon.com/javascript-es7-async-await-bible-tutorial-example-32294f6133ab#.4p2stibtt) will eventually supplement promises, although they are still really new language features.
- [Async/await](https://hackernoon.com/javascript-es7-async-await-bible-tutorial-example-32294f6133ab#.4p2stibtt) will eventually supplement promises, although they are still really new language features.

<!---
Another good reference:
http://www.2ality.com/2014/10/es6-promises-api.html
--->






0 comments on commit 9cf5439

Please sign in to comment.