You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
First, let's see the problem we're trying to avoid:
13
13
14
-
Let's start by creating a few files in a brand new directory. Use the name of the files below and the contents as described for this example. The numeric names of the file are used to help clarify the point being made.
15
-
16
-
`1.html`
17
-
{% highlight html %}
18
-
<spanclass="Speaker">Joe Andaverde</span>
19
-
<pclass="bio">Joe is a Software Engineer for Softek Solutions, Inc. He's passionate about sharing his knowledge with others.</p>
20
-
{% endhighlight %}
21
-
22
-
`2.html`
23
-
{% highlight html %}
24
-
<spanclass="Speaker">Dusty Burwell</span>
25
-
<pclass="bio">Dusty is a dude.</p>
26
-
{% endhighlight %}
27
-
28
14
{% highlight javascript %}
29
-
var fs = require('fs');
30
-
31
-
for (var i = 1; i <= 2; i++) {
32
-
fs.readFile(i + ".html", function (err, data) {
33
-
if (err) return;
34
-
35
-
var matches = data.toString().match(/<span class=\"Speaker\">([\s\S]+)<\/span>[\s\S]+<p class=\"bio\">([\s\S]+)<\/p>/i);
console.log('You might think this gets printed last.')
44
21
{% endhighlight %}
45
22
46
-
Go back to your command window and list files in your current working directory. Notice that the only file created was `3.json`. This is because the callback from read file doesn't actually get executed until the loop has completed. Any other statements after the for loop would also be executed before the callback. This is, in part, because Node is single threaded. The event loop hasn't had a chance to invoke your callback. In any case, all of the callbacks are being fired and overwriting `3.json`.
23
+
Go back to your command window and list files in your current working directory. Notice that the only file created was `3.json`. This is because the callback for setTimeout doesn't actually get executed until the for loop has completed. Any other statements after the for loop would also be executed before the callback. This is, in part, because Node is single threaded. The event loop hasn't had a chance to invoke your callback. In any case, all of the callbacks are being fired with the same value of `i`.
47
24
48
25
How do we avoid this? The important concept here is how scope is handled in JavaScript. Unlike other languages that use block level scope, JavaScript's scope is at a function level. We can get around this problem by introducing a new scope in each iteration of the loop to capture the value of `i` at that moment:
49
26
50
27
{% highlight javascript %}
51
-
var fs = require('fs');
52
-
53
-
for (var i = 1; i <= 2; i++) {
54
-
(function (i) { //Create a new scope that takes a single argument
55
-
fs.readFile(i + ".html", function (err, data) {
56
-
if (err) return;
57
-
58
-
var matches = data.toString().match(/<span class=\"Speaker\">([\s\S]+)<\/span>[\s\S]+<p class=\"bio\">([\s\S]+)<\/p>/i);
})(i);//Execute this function with the current value of i
28
+
for (var i = 0; i < 100; i++) {
29
+
(function (i) {
30
+
setTimeout(function () {
31
+
console.log(i);
32
+
}, 100);
33
+
})(i);
67
34
}
35
+
console.log('this still gets printed first.')
68
36
{% endhighlight %}
69
37
70
-
The lesson to be learned here is that new scopes are your best friend when performing asynchronous actions in JavaScript.
38
+
The lesson to be learned here is that new scopes are your best friend when performing asynchronous actions in JavaScript. A better way to do this would be to avoid creating a new function with each iteration of the loop like so:
39
+
40
+
{% highlight javascript %}
41
+
var printNumberLater = function (i) {
42
+
setTimeout(function () {
43
+
console.log(i);
44
+
}, 100);
45
+
};
46
+
47
+
for (var i = 0; i < 100; i++) {
48
+
printNumberLater(i);
49
+
}
50
+
51
+
console.log('this still gets printed first.')
52
+
{% endhighlight %}
71
53
72
54
## Asynchronous calls in parallel and then joining them
73
55
56
+
So how do we go about printing out a something after the loops work has been done.
57
+
74
58
More often than not there's a need to invoke a set of tasks asynchronously and then start a new set of tasks after completion. There are a variety of libraries that help with performing this situation and cleaning up the code a lot.
0 commit comments