<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xml:base="https://web-engineering.info"  xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
 <title>web-engineering.info - JavaScript</title>
 <link>https://web-engineering.info/JavaScript</link>
 <description></description>
 <language>en</language>
<item>
 <title>Asynchronous Programming in JavaScript</title>
 <link>https://web-engineering.info/node/83</link>
 <description>&lt;div class=&quot;field field-name-body field-type-text-with-summary field-label-hidden view-mode-rss&quot;&gt;&lt;div class=&quot;field-items&quot;&gt;&lt;div class=&quot;field-item even&quot; property=&quot;content:encoded&quot;&gt;&lt;p&gt;In programming, we often have the situation that, when calling a possibly time-consuming input/output (I/O) operation (or any long-running operation, e.g., for performing a complex computation), the program execution has to wait for its result being returned before it can go on. Calling such an operation and waiting for its result, while the main program&#039;s further execution (and its entire thread) is blocked, represents a &lt;em&gt;synchronous&lt;/em&gt; operation call. The implied waiting/blocking poses a problem for a JS program that is being executed in a browser thread since during the waiting time the user interface (in a browser tab) would be frozen, which is not acceptable from a usability point of view and therefore not accepted by browsers.&lt;/p&gt;

&lt;p&gt;Consequently, in JavaScript, it is not possible to call an I/O operation, e.g., for fetching data from a webpage (with the built-in &lt;code&gt;XMLHttpRequest&lt;/code&gt; or &lt;code&gt;fetch&lt;/code&gt; API) or for accessing a remote database (via HTTP request-response messaging) synchronously. These types of operations have to be performed in an &lt;em&gt;&lt;b&gt;asynchronous&lt;/b&gt;&lt;/em&gt; (non-blocking) manner, instead.&lt;/p&gt;

&lt;p&gt;Asynchronous programming concepts in JavaScript have undergone an evolution from &lt;em&gt;callbacks&lt;/em&gt; to &lt;em&gt;promises&lt;/em&gt; to &lt;em&gt;generators&lt;/em&gt; (coroutines) and, most recently, to &lt;em&gt;asynchronous procedure calls&lt;/em&gt; with &lt;code&gt;await&lt;/code&gt; procedure invocation expressions and asynchronous procedure definitions with &lt;code&gt;async&lt;/code&gt;. Each evolution step has made asynchronous programming a little bit easier for those who have taken the effort to get familiar with it.&lt;/p&gt;

&lt;p&gt;Due to this evolution, operations of older JS input/output APIs available in the form of built-in objects, like &lt;code&gt;XMLHttpRequest&lt;/code&gt; for HTTP messaging or &lt;code&gt;indexedDB&lt;/code&gt; for object database management, work with callbacks, while newer APIs, like &lt;code&gt;fetch&lt;/code&gt; for HTTP messaging, work with promises and can also be invoked with &lt;code&gt;await&lt;/code&gt;.&lt;/p&gt;

&lt;section&gt;
&lt;h2&gt;Callbacks&lt;/h2&gt;

&lt;p&gt;A simple asynchronous programming approach consists of defining a procedure that is to be executed as soon as the asynchronous operation completes. This allows to continue the program execution after the invocation of the asynchronous operation, however, without assuming that the operation result is available. But how does the execution environment know, which procedure to call after completing the asynchronous operation?&lt;/p&gt;

&lt;p&gt;In JS, we can pass a JS function as an argument in the invocation of the asynchronous operation. A &lt;em&gt;callback&lt;/em&gt; is such a JS function.&lt;/p&gt;

&lt;p&gt;Consider the following example. An external JS file can be dynamically loaded (in the context of an already loaded webpage with associated JS code) by (1) programmatically creating an HTML &lt;code&gt;script&lt;/code&gt; element DOM object with the file&#039;s URL as the value of the script&#039;s &lt;code&gt;src&lt;/code&gt; attribute, and (2) inserting the newly created &lt;code&gt;script&lt;/code&gt; element after the last child node of the document&#039;s &lt;code&gt;head&lt;/code&gt; element:&lt;/p&gt;

&lt;pre class=&quot;role-listing&quot;&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;function&lt;/span&gt; &lt;b&gt;loadJsFile&lt;/b&gt;( fileURL) {
  &lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; scriptEl = document.createElement(&lt;span class=&quot;hl-string&quot;&gt;&quot;script&quot;&lt;/span&gt;);
  script.src = fileURL;
  document.head.&lt;b&gt;append&lt;/b&gt;( scriptEl);
}&lt;/pre&gt;

&lt;p&gt;When the new script element is inserted into the document&#039;s DOM, e.g., with the help of the asynchronous DOM operation &lt;code&gt;append&lt;/code&gt; (at the end of the &lt;code&gt;loadJsFile&lt;/code&gt; procedure), the browser will load the JS file and then parse and execute it, which will take some time. Let&#039;s assume that we have a JS code file containing the definition of a function &lt;code&gt;addTwoNumbers&lt;/code&gt; that does what its name says and we first load the file and then invoke the function in the following way:&lt;/p&gt;

&lt;pre class=&quot;role-listing&quot;&gt;
loadJsFile(&lt;span class=&quot;hl-string&quot;&gt;&quot;addTwoNumbers.js&quot;&lt;/span&gt;);
console.log( addTwoNumbers( &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;));&lt;/pre&gt;

&lt;p&gt;This wouldn&#039;t work. We would get an error message instead of the sum of 1 and 2, since the intended result of the first statement, the availability of the &lt;code&gt;addTwoNumbers&lt;/code&gt; function, is not (yet) obtained when the second statement is executed.&lt;/p&gt;

&lt;p&gt;We can fix this by adding a callback procedure as a second parameter to the &lt;code&gt;loadJsFile&lt;/code&gt; procedure and assign it as an event handler of the JS file &lt;code&gt;load&lt;/code&gt; event :&lt;/p&gt;

&lt;pre class=&quot;role-listing&quot;&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;function&lt;/span&gt; loadJsFile( fileURL, &lt;b&gt;callback&lt;/b&gt;) {
  &lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; scriptEl = document.createElement(&lt;span class=&quot;hl-string&quot;&gt;&quot;script&quot;&lt;/span&gt;);
  script.src = fileURL;
  script.&lt;b&gt;onload&lt;/b&gt; = &lt;b&gt;callback&lt;/b&gt;;
  document.head.append( scriptEl);
}&lt;/pre&gt;

&lt;p&gt;Now when calling &lt;code&gt;loadJsFile&lt;/code&gt; we can provide the code to be executed after loading the &quot;addTwoNumbers.js&quot; file in an anonymous callback function:&lt;/p&gt;

&lt;pre class=&quot;role-listing&quot;&gt;
loadJsFile(&lt;span class=&quot;hl-string&quot;&gt;&quot;addTwoNumbers.js&quot;&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;function&lt;/span&gt; () {
  console.log( addTwoNumbers( &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;));  &lt;span class=&quot;hl-comment&quot;&gt;// results in 3&lt;/span&gt;
]);&lt;/pre&gt;

&lt;p&gt;Since the loading of the JS file can fail, we should better add some error handling for this case by defining an event handler for the &lt;code&gt;error&lt;/code&gt; event. We can handle possible errors within the &lt;i&gt;callback&lt;/i&gt; procedure by calling it with an error argument:&lt;/p&gt;

&lt;pre class=&quot;role-listing&quot;&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;function&lt;/span&gt; loadJsFile( fileURL, &lt;b&gt;callback&lt;/b&gt;) {
  &lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; scriptEl = document.createElement(&lt;span class=&quot;hl-string&quot;&gt;&quot;script&quot;&lt;/span&gt;);
  script.src = fileURL;
  script.&lt;b&gt;onload&lt;/b&gt; = &lt;b&gt;callback&lt;/b&gt;;
  script.&lt;b&gt;onerror&lt;/b&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;function&lt;/span&gt; () {
      &lt;b&gt;callback&lt;/b&gt;( &lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;Error&lt;/span&gt;(`Script load error &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; ${fileURL}`));
  };
  document.head.append( scriptEl);
}&lt;/pre&gt;

&lt;p&gt;Now we call &lt;code&gt;loadJsFile&lt;/code&gt; with an anonymous callback function having an &lt;code&gt;error&lt;/code&gt; parameter:&lt;/p&gt;

&lt;pre class=&quot;role-listing&quot;&gt;
loadJsFile(&lt;span class=&quot;hl-string&quot;&gt;&quot;addTwoNumbers.js&quot;&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;function&lt;/span&gt; (error) {
  &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; (!error) console.log( addTwoNumbers(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;));  &lt;span class=&quot;hl-comment&quot;&gt;// results in 3&lt;/span&gt;
  &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; console.log( error);
]);&lt;/pre&gt;

&lt;p&gt;Callbacks work well as an asynchronous programming approach in simple cases. But when it is necessary to perform several asynchronous operations in a sequence, one quickly ends up in a &quot;callback hell&quot;, a term that refers to the resulting deeply nested code structures that are hard to read and maintain.&lt;/p&gt;
&lt;/section&gt;

&lt;section&gt;
&lt;h2&gt;Promises&lt;/h2&gt;

&lt;p&gt;A &lt;em&gt;promise&lt;/em&gt; (also called &lt;em&gt;future&lt;/em&gt; in some programming languages, like in Python) is a special object that provides the deferred result of an asynchronous operation to the code that waits for this result. A promise object is initially in the state &lt;em&gt;pending&lt;/em&gt;. If the asynchronous operation succeeds (in the case when the &lt;code&gt;resolve&lt;/code&gt; function is called with an argument providing the result value), the promise state is changed from &lt;em&gt;pending&lt;/em&gt; to &lt;em&gt;fulfilled&lt;/em&gt;. If it fails (in the case when the &lt;code&gt;reject&lt;/code&gt; function is called with an argument providing the error), the promise state is changed from &lt;em&gt;pending&lt;/em&gt; to &lt;em&gt;rejected&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;An example of a built-in asynchronous operation that returns a promise is &lt;code&gt;import&lt;/code&gt; for dynamically loading JS code files (and ES6 modules). We can use it instead of the user-defined &lt;code&gt;loadJsFile&lt;/code&gt; procedure discussed in the previous section for loading the &lt;kbd&gt;addTwoNumbers.js&lt;/kbd&gt; file and subsequently executing code that uses the &lt;code&gt;addTwoNumbers&lt;/code&gt; function (or reporting an error if the loading failed):&lt;/p&gt;

&lt;pre class=&quot;role-listing&quot;&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&quot;addTwoNumbers.js&quot;&lt;/span&gt;)
.&lt;b&gt;then&lt;/b&gt;( &lt;span class=&quot;hl-keyword&quot;&gt;function&lt;/span&gt; () {
  console.log( addTwoNumbers( &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;));
})
.&lt;b&gt;catch&lt;/b&gt;( &lt;span class=&quot;hl-keyword&quot;&gt;function&lt;/span&gt; (error) {
  console.log( error);
});&lt;/pre&gt;

&lt;p&gt;This example code shows that on the promise object returned by &lt;code&gt;import&lt;/code&gt; we can call the predefined functions &lt;code&gt;then&lt;/code&gt; and &lt;code&gt;catch&lt;/code&gt;:&lt;/p&gt;

&lt;dl&gt;
	&lt;dt&gt;&lt;code&gt;then&lt;/code&gt;&lt;/dt&gt;
	&lt;dd&gt;for continuing the execution only when the &lt;code&gt;import&lt;/code&gt; operation is completed with a &lt;em&gt;fulfilled&lt;/em&gt; promise, and&lt;/dd&gt;
	&lt;dt&gt;&lt;code&gt;catch&lt;/code&gt;&lt;/dt&gt;
	&lt;dd&gt;for processing the error result of a &lt;em&gt;rejected&lt;/em&gt; promise.&lt;/dd&gt;
&lt;/dl&gt;

&lt;p&gt;The general approach of &lt;em&gt;asynchronous programming with promises&lt;/em&gt; requires each asynchronous operation to return a promise object that typically provides either a result value, when the promise is fulfilled, or an error value, when the promise is rejected. For user-defined asynchronous procedures, this means that they have to create a promise as their return value, as shown in the promise-valued &lt;code&gt;loadJsFile&lt;/code&gt; function presented below.&lt;/p&gt;

&lt;p&gt;A promise object can be created with the help of the &lt;code&gt;Promise&lt;/code&gt; constructor by providing an anonymous function expression as the argument of the &lt;code&gt;Promise&lt;/code&gt; constructor invocation (with two parameters &lt;code&gt;resolve&lt;/code&gt; and &lt;code&gt;reject&lt;/code&gt; representing JS functions). We do this in the following example of a promise-valued &lt;code&gt;loadJsFile&lt;/code&gt; function, which is a variant of the previously discussed callback-based &lt;code&gt;loadJsFile&lt;/code&gt; procedure:&lt;/p&gt;

&lt;pre class=&quot;role-listing&quot;&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;function&lt;/span&gt; &lt;b&gt;loadJsFile&lt;/b&gt;( fileURL) {
  &lt;span class=&quot;hl-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt; &lt;b&gt;Promise&lt;/b&gt;( &lt;span class=&quot;hl-keyword&quot;&gt;function&lt;/span&gt; (&lt;b&gt;resolve&lt;/b&gt;, &lt;b&gt;reject&lt;/b&gt;) {
    &lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; scriptEl = document.createElement(&lt;span class=&quot;hl-string&quot;&gt;&quot;script&quot;&lt;/span&gt;);
    scriptEl.src = fileURL;
    scriptEl.on&lt;b&gt;load&lt;/b&gt; = &lt;b&gt;resolve&lt;/b&gt;;
    scriptEl.on&lt;b&gt;error&lt;/b&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;function&lt;/span&gt; () {&lt;b&gt;
        reject&lt;/b&gt;( &lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;Error&lt;/span&gt;(`Script load error &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; ${fileURL}`));
    };
    document.head.append( scriptEl);
  });
}&lt;/pre&gt;

&lt;p&gt;This new version of the asynchronous &lt;code&gt;loadJsFile&lt;/code&gt; operation is used in the following way:&lt;/p&gt;

&lt;pre class=&quot;role-listing&quot;&gt;
loadJsFile(&lt;span class=&quot;hl-string&quot;&gt;&quot;addTwoNumbers.js&quot;&lt;/span&gt;)
.&lt;b&gt;then&lt;/b&gt;( &lt;span class=&quot;hl-keyword&quot;&gt;function&lt;/span&gt; () {
  console.log( addTwoNumbers( &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;));
})
.&lt;b&gt;catch&lt;/b&gt;( &lt;span class=&quot;hl-keyword&quot;&gt;function&lt;/span&gt; (error) {
  console.log( error);
});&lt;/pre&gt;

&lt;p&gt;We can see that even the syntax of a simple promise-valued function call with &lt;code&gt;then&lt;/code&gt; and &lt;code&gt;catch&lt;/code&gt; is more clear than the syntax of a callback-based asynchronous procedure call. This advantage is even more significant when it comes to chaining asynchronous procedure calls, as in the following example where we first sequentially load three JS files and then invoke their functions:&lt;/p&gt;

&lt;pre class=&quot;role-listing&quot;&gt;
loadJsFile(&lt;span class=&quot;hl-string&quot;&gt;&quot;addTwoNumbers.js&quot;&lt;/span&gt;)
.&lt;b&gt;then&lt;/b&gt;( &lt;span class=&quot;hl-keyword&quot;&gt;function&lt;/span&gt; () {
  &lt;span class=&quot;hl-keyword&quot;&gt;return&lt;/span&gt; loadJsFile(&lt;span class=&quot;hl-string&quot;&gt;&quot;multiplyBy3.js&quot;&lt;/span&gt;);})
.&lt;b&gt;then&lt;/b&gt;( &lt;span class=&quot;hl-keyword&quot;&gt;function&lt;/span&gt; () {
  &lt;span class=&quot;hl-keyword&quot;&gt;return&lt;/span&gt; loadJsFile(&lt;span class=&quot;hl-string&quot;&gt;&quot;decrementBy2.js&quot;&lt;/span&gt;);})
.&lt;b&gt;then&lt;/b&gt;( &lt;span class=&quot;hl-keyword&quot;&gt;function&lt;/span&gt; () {
  console.log( decrementBy2( multiplyBy3( addTwoNumbers(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;))));})
.&lt;b&gt;catch&lt;/b&gt;( &lt;span class=&quot;hl-keyword&quot;&gt;function&lt;/span&gt; (error) {
  console.log( error);
});&lt;/pre&gt;

&lt;p&gt;Notice that for executing a sequence of asynchronous operations with &lt;code&gt;then&lt;/code&gt;, we need to make sure that each &lt;code&gt;then&lt;/code&gt;-function returns a promise.&lt;/p&gt;

&lt;p&gt;As an alternative to the sequential execution of asynchronous operations, we may also execute them &lt;strong&gt;in parallel&lt;/strong&gt; with &lt;code&gt;Promise.all&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;role-listing&quot;&gt;
&lt;b&gt;Promise.all&lt;/b&gt;([ loadJsFile(&lt;span class=&quot;hl-string&quot;&gt;&quot;addTwoNumbers.js&quot;&lt;/span&gt;),
  loadJsFile(&lt;span class=&quot;hl-string&quot;&gt;&quot;multiplyBy3.js&quot;&lt;/span&gt;),
  loadJsFile(&lt;span class=&quot;hl-string&quot;&gt;&quot;decrementBy2.js&quot;&lt;/span&gt;)
])
.&lt;b&gt;then&lt;/b&gt;( &lt;span class=&quot;hl-keyword&quot;&gt;function&lt;/span&gt; () {
  console.log( decrementBy2( multiplyBy3( addTwoNumbers(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;))));
})
.&lt;b&gt;catch&lt;/b&gt;( &lt;span class=&quot;hl-keyword&quot;&gt;function&lt;/span&gt; (error) {console.log( error);});&lt;/pre&gt;

&lt;p&gt;Unlike &lt;code&gt;loadJsFile&lt;/code&gt;, which simply completes with a side effect (the loading of JS code), but without a result value being returned, a typical asynchronous operation returns a promise object that provides either a result value, when the promise is fulfilled, or an error value, when the promise is rejected.&lt;/p&gt;

&lt;p&gt;Let&#039;s consider another example, where we have asynchronous operations with result values. The JS built-in &lt;code&gt;fetch&lt;/code&gt; operation allows retrieving the contents of a remote resource file via sending HTTP request messages in two steps:&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;In the first step, it returns a promise that resolves with a &lt;code&gt;response&lt;/code&gt; object as its result value containing the HTTP header information retrieved.&lt;/li&gt;
	&lt;li&gt;Then, invoking the &lt;code&gt;text()&lt;/code&gt; or the &lt;code&gt;json()&lt;/code&gt; function on the previously retrieved &lt;code&gt;response&lt;/code&gt; object returns a promise that resolves to the HTTP response message&#039;s body (in the form of a string or a JSON object) when it is retrieved from the remote server.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In such a case, when we chain two or more asynchronous operation calls with result values, each successor call can be expressed as a transformation from the previous result to a new result using arrow functions as shown in line 2 of the following example:&lt;/p&gt;

&lt;pre class=&quot;role-listing&quot;&gt;
&lt;b&gt;fetch&lt;/b&gt;(&lt;span class=&quot;hl-string&quot;&gt;&quot;user1.json&quot;&lt;/span&gt;)
.then( response =&amp;gt; response.&lt;b&gt;json&lt;/b&gt;())
.then( &lt;span class=&quot;hl-keyword&quot;&gt;function&lt;/span&gt; (user1) {alert( user1.name);})
.&lt;span class=&quot;hl-keyword&quot;&gt;catch&lt;/span&gt;( &lt;span class=&quot;hl-keyword&quot;&gt;function&lt;/span&gt; (error) {console.log( error);});&lt;/pre&gt;

&lt;p&gt;Notice that the text file &quot;user1.json&quot; is assumed to contain a JSON object describing a particular user with a &lt;i&gt;name&lt;/i&gt; field. This JSON object is retrieved with the arrow function expression in line 2.&lt;/p&gt;
&lt;/section&gt;

&lt;section&gt;
&lt;h2&gt;Calling asynchronous operations with &lt;code&gt;await&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;When a program with a statement containing an asynchronous procedure call (with &lt;code&gt;await&lt;/code&gt;) is executed, the program will run up to that statement, call the procedure, and suspend execution until the asynchronous procedure execution completes, which means that if it returns a Promise, it is &lt;em&gt;settled&lt;/em&gt;. That suspension of execution means that control is returned to the event loop, such that other asynchronous procedures also get a chance to run. If the Promise of the asynchronous procedure execution is fulfilled, the execution of the program is resumed and the value of the &lt;code&gt;await&lt;/code&gt; expression is that of the fulfilled Promise. If it is rejected, the &lt;code&gt;await&lt;/code&gt; expression throws the value of the rejected Promise (its error).&lt;/p&gt;

&lt;p&gt;When we use &lt;code&gt;await&lt;/code&gt; for invoking a Promise-valued JS function, we typically do not use Promise chaining with &lt;code&gt;.then&lt;/code&gt;, because &lt;code&gt;await&lt;/code&gt; handles the waiting for us. And we can use a regular &lt;code&gt;try-catch&lt;/code&gt; block instead of a Promise chaining &lt;code&gt;.catch&lt;/code&gt; clause, as shown in the following example code:&lt;/p&gt;

&lt;pre class=&quot;role-listing&quot;&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;try&lt;/span&gt; {
  &lt;b&gt;await&lt;/b&gt; loadJsFile(&lt;span class=&quot;hl-string&quot;&gt;&quot;addTwoNumbers.js&quot;&lt;/span&gt;);
  console.log( addTwoNumbers(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;,&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;));
} &lt;span class=&quot;hl-keyword&quot;&gt;catch&lt;/span&gt; (error) {
  console.log( error);
}&lt;/pre&gt;

&lt;p&gt;Notice that this is the code of an ES6 module. In a normal JS file, &lt;code&gt;await&lt;/code&gt; can only be used within &lt;code&gt;async&lt;/code&gt; functions.&lt;/p&gt;

&lt;p&gt;When we call several asynchronous procedures in succession with &lt;code&gt;await&lt;/code&gt;, the code reads in a natural way, similar to the code for calling synchronous procedures:&lt;/p&gt;

&lt;pre class=&quot;role-listing&quot;&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;try&lt;/span&gt; {
  &lt;b&gt;await&lt;/b&gt; loadJsFile(&lt;span class=&quot;hl-string&quot;&gt;&quot;addTwoNumbers.js&quot;&lt;/span&gt;);
  &lt;b&gt;await&lt;/b&gt; loadJsFile(&lt;span class=&quot;hl-string&quot;&gt;&quot;multiplyBy3.js&quot;&lt;/span&gt;);
  &lt;b&gt;await&lt;/b&gt; loadJsFile(&lt;span class=&quot;hl-string&quot;&gt;&quot;decrementBy2.js&quot;&lt;/span&gt;);
  console.log( decrementBy2( multiplyBy3( addTwoNumbers(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;,&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;))));
} &lt;span class=&quot;hl-keyword&quot;&gt;catch&lt;/span&gt; (error) {
  console.log( error);
}&lt;/pre&gt;

&lt;p&gt;In an &lt;code&gt;async&lt;/code&gt; function, we can invoke Promise-valued functions in &lt;code&gt;await&lt;/code&gt; expressions. Since an &lt;code&gt;async&lt;/code&gt; function returns a Promise, it can itself be invoked with &lt;code&gt;await&lt;/code&gt;.&lt;/p&gt;

&lt;pre class=&quot;role-listing&quot;&gt;
&lt;b&gt;async&lt;/b&gt; &lt;span class=&quot;hl-keyword&quot;&gt;function&lt;/span&gt; load3JsFiles() {
  &lt;b&gt;await&lt;/b&gt; loadJsFile(&lt;span class=&quot;hl-string&quot;&gt;&quot;addTwoNumbers.js&quot;&lt;/span&gt;);
  &lt;b&gt;await&lt;/b&gt; loadJsFile(&lt;span class=&quot;hl-string&quot;&gt;&quot;multiplyBy3.js&quot;&lt;/span&gt;);
  &lt;b&gt;await&lt;/b&gt; loadJsFile(&lt;span class=&quot;hl-string&quot;&gt;&quot;decrementBy2.js&quot;&lt;/span&gt;);
}
&lt;span class=&quot;hl-keyword&quot;&gt;try&lt;/span&gt; {
  &lt;b&gt;await&lt;/b&gt; load3JsFiles();
  console.log( decrementBy2( multiplyBy3( addTwoNumbers(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;,&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;))));
} &lt;span class=&quot;hl-keyword&quot;&gt;catch&lt;/span&gt; (error) {
  console.log( error);
}&lt;/pre&gt;

&lt;p&gt;In the more typical case of asynchronous operation calls with result values, we obtain code like the following await-based version of the above promise-based example of using &lt;code&gt;fetch&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;role-listing&quot;&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;try&lt;/span&gt; {
  &lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; response = &lt;b&gt;await&lt;/b&gt; fetch(&lt;span class=&quot;hl-string&quot;&gt;&quot;user1.json&quot;&lt;/span&gt;);
  &lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; user1 = &lt;b&gt;await&lt;/b&gt; response.json();
  alert( user1.name);
} &lt;span class=&quot;hl-keyword&quot;&gt;catch&lt;/span&gt; (error) {
  console.log( error);
}&lt;/pre&gt;

&lt;p&gt;For more about asynchronous programming techniques, see &lt;a href=&quot;https://javascript.info/async&quot;&gt;Promises, async/await&lt;/a&gt; and &lt;a href=&quot;https://yunchi.dev/posts/demystifying-async/&quot;&gt;Demystifying Async Programming in Javascript&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;section class=&quot;field field-name-field-category field-type-taxonomy-term-reference field-label-above view-mode-rss&quot;&gt;&lt;h2 class=&quot;field-label&quot;&gt;Category:&amp;nbsp;&lt;/h2&gt;&lt;ul class=&quot;field-items&quot;&gt;&lt;li class=&quot;field-item even&quot;&gt;&lt;a href=&quot;/JavaScript&quot; typeof=&quot;skos:Concept&quot; property=&quot;rdfs:label skos:prefLabel&quot; datatype=&quot;&quot;&gt;JavaScript&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/section&gt;&lt;div class=&quot;easy_social_box clearfix horizontal easy_social_lang_und&quot;&gt;
            &lt;div class=&quot;easy_social-widget easy_social-widget-twitter first&quot;&gt;&lt;a href=&quot;http://twitter.com/share&quot; class=&quot;twitter-share-button&quot;
data-url=&quot;https://web-engineering.info/node/83&quot;
data-count=&quot;horizontal&quot;
data-lang = &quot;en&quot;
data-via=&quot;&quot;
data-related=&quot;:Check it out!&quot;
data-text=&quot;Asynchronous Programming in JavaScript&quot;&gt;Tweet&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&quot;easy_social-widget easy_social-widget-facebook&quot;&gt;&lt;fb:like href=&quot;https://web-engineering.info/node/83&quot; send=&quot;true&quot; layout=&quot;button_count&quot; width=&quot;88&quot; show_faces=&quot;true&quot; action=&quot;like&quot; colorscheme=&quot;light&quot; font=&quot;&quot;&gt;&lt;/fb:like&gt;&lt;/div&gt;
          &lt;div class=&quot;easy_social-widget easy_social-widget-googleplus&quot;&gt;&lt;div class=&quot;g-plusone&quot; data-size=&quot;medium&quot; data-annotation=&quot;bubble&quot; data-href=&quot;https://web-engineering.info/node/83&quot;&gt;&lt;/div&gt;&lt;/div&gt;
          &lt;div class=&quot;easy_social-widget easy_social-widget-linkedin last&quot;&gt;&lt;script type=&quot;in/share&quot; data-url=&quot;https://web-engineering.info/node/83&quot; data-counter=&quot;right&quot;&gt;&lt;/script&gt;&lt;/div&gt;
  &lt;/div&gt; &lt;!-- /.easy_social_box --&gt;</description>
 <pubDate>Thu, 01 Jul 2021 12:36:44 +0000</pubDate>
 <dc:creator>gwagner</dc:creator>
 <guid isPermaLink="false">83 at https://web-engineering.info</guid>
 <comments>https://web-engineering.info/node/83#comments</comments>
</item>
<item>
 <title>JavaScript-Based IoT/WoT Development with the ESP8266 and the Raspberry Pi</title>
 <link>https://web-engineering.info/node/65</link>
 <description>&lt;div class=&quot;field field-name-body field-type-text-with-summary field-label-hidden view-mode-rss&quot;&gt;&lt;div class=&quot;field-items&quot;&gt;&lt;div class=&quot;field-item even&quot; property=&quot;content:encoded&quot;&gt;&lt;p&gt;The ESP8266 micro-controller&amp;nbsp;module gained huge popularity over the last few years, being a small module with a powerful MCU, SPI Flash, 2.4GHz 802.11 b/g/n WiFi capabilities and relatively small power consumption, all for just a few dollars. This article focuses on discussing how to use JavaScript to program an ESP8266. Currently, two firmware versions allow JavaScript code execution on an ESP8266: &lt;a href=&quot;https://github.com/cesanta/mongoose-iot&quot;&gt;Mongoose-IoT&lt;/a&gt; (that we&#039;ll discuss about in this tutorial) and &lt;a href=&quot;http://www.espruino.com/EspruinoESP8266&quot;&gt;Espruino for ESP8266&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With a single small and cheap board, it is possible to have a JavaScript interpreter, WiFi client, WiFi router, HTTP client and server and GPIOs control, therefore allowing to read sensors, control actuators and use human interface devices, such as displays, buttons or joysticks.&lt;/p&gt;

&lt;h2&gt;Meet the ESP8266&lt;/h2&gt;

&lt;p&gt;Various modules built around the ESP8266 IC are available, and the most common 12 standard modules are shown in &lt;a href=&quot;#fig1&quot;&gt;Figure 1&lt;/a&gt;.&lt;/p&gt;

&lt;figure id=&quot;fig1&quot;&gt;&lt;a href=&quot;http://web-engineering.info/sites/default/files/wot_tutorials/Mongoose-IoT-ESP8266/esp8266-variants.png&quot;&gt;&lt;img alt=&quot;ESP8266 Module Variants&quot; src=&quot;http://web-engineering.info/sites/default/files/wot_tutorials/Mongoose-IoT-ESP8266/esp8266-variants.png&quot; /&gt;&lt;/a&gt;

&lt;figcaption&gt;Figure 1: Variants of the ESP8266 Module.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;These modules use the 802.11b/g/n WiFi standard, operating at 2.4 GHz. It means they can connect to a standard WiFi network, such as the ones provided by an WiFi router, WiFi repeater or access point (AP). No need for special communication channels or frequencies, such as the 433MHz band required by some wireless modules.&lt;/p&gt;

&lt;h3&gt;Choosing the Appropriate ESP8266 Module for a Project&lt;/h3&gt;

&lt;p&gt;Having multiple variants of ESP8266 module, comes the question: &quot;which one should I use ?&quot;. There is no perfect answer for this question, and it highly depends on what you are using the WiFi module for. These are not just &quot;blind&quot; WiFi communication modules, but small development boards, containing a programmable MCU and builtin GPIO pins, thus it can do tasks similar with the ones possible with the Arduino boards, but being much faster and in some sense more capable. We see three main points to be considered when choosing an ESP8266 module for a specific project:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;usability on a breadboard:&lt;/strong&gt; most of the times we prototype on a breadboard, therefore we should be able to easily connect (or plug) these modules to such a board. Some of the modules, such as ESP02, ESP03 and ESP05 (see &lt;a href=&quot;#fig1&quot;&gt;Figure 1&lt;/a&gt;) are breadboard friendly, having a pitch of 2.54mm (the distance between two pins). Other modules, such as ESP07 or ESP08 have a pitch of 1.27mm, thus you&#039;ll only be able to use them with a breadboard when using an adapter. Last, other modules, such as ESP01 have a pitch of 2.54mm, but they have a two rows header, which makes it impossible to be used with a breadboard, because of the implied short-circuit between the pins. Notice that some of the breadboard friendly modules have only a &quot;half-way&quot; pin connections, e.g., ESP02 module. Such connections are somehow harder to solder, specially for a beginner. Our tip for the ESP02 module: plug the pin headers into a breadboard, align the module on top of them, then solder.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;flash memory size:&lt;/strong&gt; the ESP8266 modules come with permanent flash memory ranging from 4MBit (512KB) up to 16MBit (2MB), but some may even go up to 128MBit (16MB). In many cases, it is also possible to increase the flash capacity of such a module, but for this, one needs good soldering skills to remove the old flash IC and solder the new one, and usually the price of the flash IC bought in small quantities is about the same as for the price of the complete ESP8266 module (or even more!), thus defeating the purpose. Excepting the case of ESP06, ESP07, ESP08 and ESP12E/F modules, where a hard to remove metallic shield covers the CPU and flash ICs, one can simply check the flash size by reading the text on the 8 pin black IC soldered near the MCU (which is the square black IC with pins on all four sides). For example, if the number on the flash IC starts with 25Q80 then it is a 8MBit Flash, while if it starts with 25Q40 then it is a 4MBit one. For our purpose, a minimum of 1MB (8MBit) Flas is required, but we recommend 4MB+ (16MBit+).&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;MCU features:&lt;/strong&gt; these modules are driven by a low power 32-bit RISC CPU (Tensilica Xtensa LX106) running at 80 MHz. It has 64 KB instructions RAM, 96 KB data RAM, it and supports external QSPI flash - 512 KB to 4 MB (but also up to 16MB is supported). Up to 16 GPIO pins are available, from which one has 10Bit ADC capabilities, and supports I2C, I2S, SPI and UART communication protocols. All these features are quite important if you are using the ESP8266 module as standalone controller board. However, if the ESP8266 module is used as an UART WiFi interface only, then you&#039;ll not really use the GPIO pins, so you may ignore this when selecting the board that suits your needs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; for being able to write a new firmware or to communicate with an ESP module by using a computer, you&#039;ll need a USB-TTL module, such as the CP2102 IC based one, shown in &lt;a href=&quot;fig4&quot;&gt;Figure 4&lt;/a&gt;. You&#039;ll need to connect the TX pin of the USB-TTL module to the RX pin of the ESP module, and the RX pin of the USB-TTL module to the TX pin of the ESP module. For being able to flash a new firmware, but NOT when using the ESP module in normal mode, you&#039;ll also need to connect the GPIO0 pin of the ESP module to ground then perform a power cycle.&lt;/p&gt;

&lt;figure id=&quot;fig4&quot;&gt;&lt;img alt=&quot;USB-TTP Module based on CP2102 IC&quot; src=&quot;http://web-engineering.info/sites/default/files/wot_tutorials/Mongoose-IoT-ESP8266/usb_ttl_module.png&quot; /&gt;
&lt;figcaption&gt;Figure 4: USB-TTP Module based on CP2102 IC.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3&gt;Standalone User Friendly ESP8266 based Modules&lt;/h3&gt;

&lt;p&gt;Other ESP8266 based modules are designed with &quot;make it simple, for anyone&quot; in mind. Usually these provide a two rows breadboard friendly PCB, with USB (usually via a micro USB cable) connection, both for providing power (also by using a standard micro USB charger) and if needed, also for the communication with a PC. &lt;a href=&quot;#fig2&quot;&gt;Figure 2&lt;/a&gt; shows the NodeMCU V2 board, designed by Amica, providing an on-board CP2102 USB-TTL IC, allowing to communicate with the PC via the same micro USB cable that also used to power it. &lt;a href=&quot;#fig3&quot;&gt;Figure 3&lt;/a&gt; shows a &lt;a href=&quot;https://www.wemos.cc/product/d1-mini.html&quot;&gt;WeMOS D1 Mini&lt;/a&gt; module, designed to use &lt;a href=&quot;https://www.wemos.cc/D1-mini-Shields&quot;&gt;stackable expansions boards&lt;/a&gt; (similar with the &lt;a href=&quot;https://www.arduino.cc/en/Main/arduinoShields&quot;&gt;Arduino Shields&lt;/a&gt;), thus being able to attach various sensors, actuators or even OLED LCDs.&lt;/p&gt;

&lt;figure id=&quot;fig2&quot;&gt;&lt;img alt=&quot;Amica NodeMCU v2&quot; src=&quot;http://web-engineering.info/sites/default/files/wot_tutorials/Mongoose-IoT-ESP8266/amica_nodemcu_v2.png&quot; /&gt;
&lt;figcaption&gt;Figure 2: Amica NodeMCU v2 Module.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure id=&quot;fig3&quot;&gt;&lt;img alt=&quot;WeMOS D1 Mini&quot; src=&quot;http://web-engineering.info/sites/default/files/wot_tutorials/Mongoose-IoT-ESP8266/wemos_d1_mini.png&quot; /&gt;
&lt;figcaption&gt;Figure 3: WeMOS D1 Mini Module.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2&gt;Some Words Before Getting Started...&lt;/h2&gt;

&lt;p&gt;Before going further with the reading and following the tutorial instructions, is good to know that:&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;&lt;strong&gt;we are going to use an ESP8266 NodeMCU V2 board&lt;/strong&gt;, produced by Amica (see &lt;a href=&quot;#fig2&quot;&gt;Figure 2&lt;/a&gt;), which means: a) there is no need to put it to &quot;flashing mode&quot;, since this happens automatically, the bundled USB-TTL CP2102 IC takes care of this task; b) is powered via the micro USB cable directly from an USB port, the same port being also used for the communication with the module, if this is needed (e.g., for programming the module)&lt;/li&gt;
	&lt;li&gt;the further provided instructions presumes that &lt;strong&gt;a Raspberry Pi 2/3 board running Raspbian is used&lt;/strong&gt;, but other Linux distribution, on either a RPi 2/3 board or a PC works too, however some differences may occur with respect to some commands and Linux repositories used to obtain the required components&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;the ESP8266 12E/F modules&lt;/strong&gt; (see &lt;a href=&quot;#fig1&quot;&gt;Figure 1&lt;/a&gt;) should work well, as an alternative to NodeMCU board, but its GPIO0 pin must be pulled LOW to set the module to &quot;flashing mode&quot;, task required ONLY when the firmware needs an upgrade, and then a power cycle between the &quot;flashing mode&quot; and &quot;normal operational mode&quot; is also required - other ESP8266 modules may also work, but usually they either have less exposed GPIO pins or they are not breadboard friendly&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;the SPI Flash IC of the ESP8266 module must be 1MB+&lt;/strong&gt;, otherwise the module will not work properly or may not work at all&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;a Windows PC can also be used, and this makes the process of writing the firmware to ESP8266 module easier&lt;/strong&gt;, but various other changes are needed for being able to build the Mongoose-IoT firmware from source code, when you need custom functionality which requires firmware code changes - unfortunatelly, compiling the Mongoose-IoT firmware on a Windows machine is a real pain&lt;/li&gt;
	&lt;li&gt;further on, we&#039;ll use &lt;strong&gt;MFT as a short name for the &quot;Mongoose-IoT Flashing Tool&quot; software, ESP as a short name for the ESP8266 module&lt;/strong&gt; (full name is used if needed to make distinction in some cases, when just ESP is confusing) and &lt;strong&gt;RPi as a short name for &quot;Raspberry Pi 3 Model B&quot;&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Flashing the Standard Mongoose-IoT Firmware by Using an Raspberry Pi&lt;/h2&gt;

&lt;p&gt;For being able to execute JavaScript code on your ESP module requires to upload the &lt;a href=&quot;https://github.com/cesanta/mongoose-iot&quot;&gt;Mongoose-IoT firmware&lt;/a&gt;. It uses the &lt;a href=&quot;https://github.com/cesanta/v7&quot;&gt;V7&lt;/a&gt; JavaScript engine and allows to execute standard JavaScript code. Notice that only a subset of the standard JavaScript is supported, and some of the features are stripped down, so the V7 engine &quot;fits&quot; on the ESP module. For example, some &lt;code&gt;String&lt;/code&gt; related check/manipulation methods (e.g., &lt;code&gt;startsWith&lt;/code&gt; and &lt;code&gt;endsWith&lt;/code&gt;) and the new ECMA5 features may not be (at all or fully) supported. However, it comes with additional features, which are not available as part of the standard JavaScript core, but a being available on NodeJS (i.e., stripped down modules or core functionality), such as the HTTP client (allowing for HTTP requests) and HTTP server capabilities.&lt;/p&gt;

&lt;h3&gt;Build the Mongoose Flashing Tool Application&lt;/h3&gt;

&lt;p&gt;The latest standard Mongoose-IoT firmware version can be obtained by using the MFT software. Compiling and building it from source code requires quite some time (about 2+ hours) to complete, and lots of space on your RPi storage (3GB+, but most of it can be recovered at the end), because it needs to download and compile the &lt;a href=&quot;https://www.qt.io&quot;&gt;Qt Framework&lt;/a&gt;. The following steps guides you through the process of installing MFT on your RPi:&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;make sure that your RPi has internet connection (either WiFi or wired connection)&lt;/li&gt;
	&lt;li&gt;install dependencies required further in the build and compile processes:&lt;br /&gt;
	&lt;code class=&quot;consoleCode&quot;&gt;# sudo apt-get install build-essential git python-git wget libglib2.0-dev libudev-dev libftdi-dev libfontconfig1-dev libjpeg-dev libssl-dev libicu-dev libjpeg-dev libxcb-xinerama0-dev libxcb-icccm4-dev libxcb-image0-dev libxcb-keysyms1-dev libxcb-render-util0-dev libxcb-shm0-dev libxi-dev libxrender-dev x11proto-render-dev qt5-qmake libqt5serialport5-dev libxcb-util0 libffi-dev &lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;configure, build and install the Qt static libraries by executing: &lt;code class=&quot;consoleCode&quot;&gt; # wget -c http://download.qt.io/official_releases/qt/5.7/5.7.0/single/qt-everywhere-opensource-src-5.7.0.tar.gz&lt;br /&gt;
	&lt;br /&gt;
	# tar xzf qt-everywhere-opensource-src-5.7.0.tar.gz&lt;br /&gt;
	&lt;br /&gt;
	# cd qt-everywhere-opensource-src-5.7.0&lt;br /&gt;
	&lt;br /&gt;
	# ./configure -make &#039;libs tools&#039; -static -prefix /opt/qt5 -opensource -confirm-license -skip qt3d -skip qtcanvas3d -skip qtdoc -skip qtlocation -skip qtscript -skip qtmultimedia -skip qtsensors -skip qtwebengine&lt;br /&gt;
	&lt;br /&gt;
	# sudo nice make -j4&lt;br /&gt;
	&lt;br /&gt;
	# sudo nice make -j4 install&lt;br /&gt;
	&lt;br /&gt;
	# sudo /opt/qt5/bin/qmake &amp;amp;&amp;amp; nice make -j 4&lt;/code&gt;&lt;br /&gt;
	...now take a cafe and watch some YouTube videos, this task takes quite some time to complete (approx. 80 minutes on our RPi 3B board). Some Qt5 extensions were excluded since we don&#039;t really need them for our purpose and thus the compilation time is cut down.&lt;br /&gt;
	&lt;strong&gt;Note:&lt;/strong&gt; each line starting with a dash (#) is a new command, and you should not write the # when executing this. You can execute the commands one by one or as a batch, on your RPi console of via SSH.&lt;/li&gt;
	&lt;li&gt;ensure that your beloved RPi does not overheat during the above tasks (specially when building Qt), so from time to time check the CPU temperature by using&lt;br /&gt;
	&lt;code class=&quot;consoleCode&quot;&gt;sudo /opt/vc/bin/vcgencmd measure_temp&lt;/code&gt;&lt;br /&gt;
	and make sure that the temperature stays below 80°C / 176°F. Blow some air by using a cooler or place your RPi somewhere in a good ventilated area. In our case the temperature did not exceeded 60°C, on a room with temperature of about 24°C, but a cooler was used to move the air around, because our RPi is a bare board with no heatsinks or any other cooling method.&lt;br /&gt;
	&lt;strong&gt;Note:&lt;/strong&gt; for single core RPi boards (RPi 1 Model B), do not use the &quot;-j&quot; parameter, e.g., &lt;code&gt;sudo nice make -j 4&lt;/code&gt; (or any other task), since this parameter is being used to specify the number of CPU cores to be used during that task, so it fails with a value of &quot;4&quot; (or any other) when used with single core CPUs (e.g., &lt;a href=&quot;https://www.raspberrypi.org/products/pi-zero/&quot;&gt;Raspberry Pi Zero&lt;/a&gt; or &lt;a href=&quot;https://www.raspberrypi.org/products/model-b/&quot;&gt;Raspberry Pi 1 Model B&lt;/a&gt;).&lt;/li&gt;
	&lt;li&gt;clone the &lt;a href=&quot;https://github.com/cesanta/mongoose-flashing-tool&quot;&gt;Mongoose Flashing Tool Repository&lt;/a&gt; - thus getting the latest available source code:&lt;br /&gt;
	&lt;code class=&quot;consoleCode&quot;&gt;# git clone https://github.com/cesanta/mongoose-flashing-tool.git&lt;/code&gt;&lt;br /&gt;
	in a folder at your choice&lt;/li&gt;
	&lt;li&gt;enter the newly source code folder, by using:&lt;br /&gt;
	&lt;code class=&quot;consoleCode&quot;&gt;# cd mongoose-flashing-tool&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;execute:&lt;br /&gt;
	&lt;code class=&quot;consoleCode&quot;&gt;# QT_SELECT=5 /opt/qt5/bin/qmake &amp;amp;&amp;amp; make -j 3&lt;/code&gt;&lt;br /&gt;
	to build MFT from source. This step may take some time to complete (about 2 minutes on our RPi 3B)&lt;/li&gt;
	&lt;li&gt;in case that the above step results in one or all of the build errors:&lt;br /&gt;
	&lt;code&gt;/usr/bin/ld: cannot find -lEGL&lt;br /&gt;
	/usr/bin/ld: cannot find -lGLESv2&lt;/code&gt;&lt;br /&gt;
	then your OpenGL static libraries cannot be linked, probably because are not found, because normally their shared versions are available on Raspbian. To solve this you need to edit the &lt;code&gt;mongoose-flashing-tool/src/Makefile&lt;/code&gt; file, by using whatever editor you like. Notice that this file DO NOT existst before trying to compile MFT, you can only find it afterwards (even if you get the error, the file must be there). In this file, find the following &lt;code&gt;-lEGL&lt;/code&gt; and &lt;code&gt;-lGLESv2&lt;/code&gt; and delete them. Then at the end of the line where you found these two, add the following: &lt;code&gt;-Wl,-Ddynamic -L/opt/vc/lib -l:libEGL.so -l:libGLESv2.so&lt;/code&gt;, then save the file and execute the &lt;code&gt;QT_SELECT=5 /opt/qt5/bin/qmake &amp;amp;&amp;amp; make -j 3&lt;/code&gt; command again (make sure that you are in the &lt;code&gt;mongoose-flashing-tool&lt;/code&gt; folder and NOT in its &lt;code&gt;src&lt;/code&gt; sub-folder when doing this).&lt;/li&gt;
	&lt;li&gt;at this point you must connect the ESP module (e.g., NodeMCU, WeMOS or a standard one with an attached USB-TTL bridge) to an USB port of your RPi board,by using a corresponding USB cable and any of the USB ports of your RPi board&lt;/li&gt;
	&lt;li&gt;start the MFT application by executing:&lt;br /&gt;
	&lt;code class=&quot;consoleCode&quot;&gt;# cd src&lt;br /&gt;
	# ./MFT&lt;/code&gt;&lt;br /&gt;
	and the application must start in GUI mode and should detect the module type (ESP8266). Make sure that you select the correct port (e.g., &lt;code&gt;ttyUSB0&lt;/code&gt; in our case), then follow the instructions, as also shown in &lt;a href=&quot;fig5&quot;&gt;Figure 5&lt;/a&gt;, &lt;a href=&quot;fig6&quot;&gt;Figure 6&lt;/a&gt;, &lt;a href=&quot;fig7&quot;&gt;Figure 7&lt;/a&gt;, and &lt;a href=&quot;fig8&quot;&gt;Figure 8&lt;/a&gt;.&lt;/li&gt;
	&lt;li&gt;if your ESP module refuses connection for firmware update (it happens normally only with the basic ESP modules, see &lt;a href=&quot;#fig1&quot;&gt;Figure 1&lt;/a&gt;, but should not be the case for NodeMCU and WeMOS D1 Mini boards), it usually means that the module did not entered &quot;flashing mode&quot;, so you may want to check if the GPIO0 pin is pulled LOW (do this task without supplying power to the board!), i.e., connected to GND rail, and make sure to power cycle the module after pulling LOW the GPIO0 pin&lt;/li&gt;
	&lt;li&gt;now you can remove the source folders for the Qt5 library, this freeing up 3GB+ on the RPi SD/MicroSD card, by executing:&lt;br /&gt;
	&lt;code&gt;# rm -rf qt-everywhere-opensource-src-5.7.0&lt;/code&gt;&lt;br /&gt;
	from the parent folder of &lt;code&gt;qt-everywhere-opensource-src-5.7.0&lt;/code&gt; folder. If permission denied errors occurs, then execute the command with &lt;code&gt;sudo&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you find the build process too complicated, but still want to try the ESP8266 firmware, then download the compiled MFT application for Raspbian (tested on 20 October 2016) from the link below. Unzip the archive by executing &lt;code&gt;unzip mongoose-flashing-tool.zip&lt;/code&gt;, and give execution rights to the &lt;code&gt;src/MFT&lt;/code&gt; application, by using &lt;code&gt;sudo u+x src/MFT&lt;/code&gt; from the &lt;code&gt;mongoose-flashing-tool&lt;/code&gt; folder. Finally, install the &lt;code&gt;libxcb&lt;/code&gt; dependency library, by using &lt;code&gt;sudo apt-get install libxcb-util0&lt;/code&gt;. Now you can run the application by using &lt;code&gt;src/MFT&lt;/code&gt; from the &lt;code&gt;mongoose-flashing-tool&lt;/code&gt; folder or simply &lt;code&gt;./MFT&lt;/code&gt; from the &lt;code&gt;mongoose-flashing-tool/src&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://web-engineering.info/sites/default/files/wot_tutorials/Mongoose-IoT-ESP8266/mongoose-flashing-tool.zip&quot; style=&quot;padding: 
2px 3px; margin: 1em; border: 1px solid black;&quot;&gt;Download Mongoose Flashing Tool (MFT) Build for Raspbian&lt;/a&gt;&lt;/p&gt;

&lt;figure id=&quot;fig5&quot;&gt;&lt;img alt=&quot;MFT - Select ESP8266 Module and Communication Port&quot; src=&quot;http://web-engineering.info/sites/default/files/wot_tutorials/Mongoose-IoT-ESP8266/MFT_screenshoot_module_and_port.png&quot; /&gt;
&lt;figcaption&gt;Figure 5: Mongoose-IoT Flashing Tool - Select Module and Communication Port.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure id=&quot;fig6&quot;&gt;&lt;img alt=&quot;MFT - Select Firmware&quot; src=&quot;http://web-engineering.info/sites/default/files/wot_tutorials/Mongoose-IoT-ESP8266/MFT_screenshoot_select_firmware.png&quot; /&gt;
&lt;figcaption&gt;Figure 6: Mongoose-IoT Flashing Tool - Select Firmware.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure id=&quot;fig7&quot;&gt;&lt;img alt=&quot;MFT - Flashing the Firmware&quot; src=&quot;http://web-engineering.info/sites/default/files/wot_tutorials/Mongoose-IoT-ESP8266/MFT_screenshoot_flashing_firmware.png&quot; /&gt;
&lt;figcaption&gt;Figure 7: Mongoose-IoT Flashing Tool - Flashing the Firmware.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure id=&quot;fig8&quot;&gt;&lt;img alt=&quot;MFT - Connect to WiFi Network&quot; src=&quot;http://web-engineering.info/sites/default/files/wot_tutorials/Mongoose-IoT-ESP8266/MFT_screenshoot_connect_to_wifi.png&quot; /&gt;
&lt;figcaption&gt;Figure 8: Mongoose-IoT Flashing Tool - Connect to WiFi Network.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Connecting the ESP8266 module to a WiFi network (see &lt;a href=&quot;fig7&quot;&gt;Figure 8&lt;/a&gt;), is optional, and you can do this later when the module needs access to Internet or Intranet. Therefore, after the step shown in &lt;a href=&quot;#fig7&quot;&gt;Figure 7&lt;/a&gt; you can already close the MFT application.&lt;/p&gt;

&lt;h3&gt;First JavaScript Tests on ESP8266&lt;/h3&gt;

&lt;p&gt;Lets test now our new JavaScript toy! For this, from the folder &lt;code&gt;mongoose-flashing-tool/src&lt;/code&gt;, execute:&lt;br /&gt;
&lt;code class=&quot;consoleCode&quot;&gt;./MFT --advanced&lt;/code&gt;&lt;br /&gt;
which opens the same MFT application, this time in an advanced mode where you can interact with the ESP module, using some kind of console like style (see &lt;a href=&quot;fig9&quot;&gt;Figure 9&lt;/a&gt;). Then, select the communication port (should be the same as the one used when writing the firmware), and click the &lt;code&gt;Connect&lt;/code&gt; button. If all went fine, you must be connected to your ESP module.&lt;/p&gt;

&lt;p&gt;As a simple test, lets check the current configuration of your ESP module, currently running on the Mongoose-IoT firmware. For this, in the MFT Console, write &lt;code&gt;Sys.conf&lt;/code&gt; then press &lt;code&gt;Enter&lt;/code&gt;. As result, the serialized JavaScript configuration object is shown (see &lt;a href=&quot;fig10&quot;&gt;Figure 10&lt;/a&gt;).&lt;/p&gt;

&lt;figure id=&quot;fig9&quot;&gt;&lt;img alt=&quot;MFT - Connect ESP8266 Module&quot; src=&quot;http://web-engineering.info/sites/default/files/wot_tutorials/Mongoose-IoT-ESP8266/MFT_screenshoot_connect_to_esp8266.png&quot; /&gt;
&lt;figcaption&gt;Figure 9: Mongoose-IoT Flashing Tool - Connect to ESP8266 Module.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure id=&quot;fig10&quot;&gt;&lt;a href=&quot;http://web-engineering.info/sites/default/files/wot_tutorials/Mongoose-IoT-ESP8266/MFT_screenshoot_javascript_test_esp8266.png&quot;&gt;&lt;img alt=&quot;MFT - AFirst JavaScript Test Code on ESP8266&quot; src=&quot;http://web-engineering.info/sites/default/files/wot_tutorials/Mongoose-IoT-ESP8266/MFT_screenshoot_javascript_test_esp8266.png&quot; /&gt;&lt;/a&gt;

&lt;figcaption&gt;Figure 10: Mongoose-IoT Flashing Tool - A First JavaScript Test Code on ESP8266.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;One more test we like to do, is to upload a JavaScript file, containing some code that we like to execute on ESP8266. For this, create a file named &lt;code&gt;app.js&lt;/code&gt; on a folder at your choice, then using a text editor, open it and copy/paste the following simple test code:&lt;/p&gt;

&lt;pre&gt;
function sum(a, b) {return a+b;};
console.log( &quot;The sum of 123 and 456 is: &quot; + sum( 123, 456));
&lt;/pre&gt;

&lt;p&gt;Use the &lt;code&gt;Upload File&lt;/code&gt; button, and and select the &lt;code&gt;app.js&lt;/code&gt; JavaScript file to be uploaded to your ESP8266 module. Reboot the module, using the &lt;code&gt;Reboot&lt;/code&gt; button, then in a few seconds, after some initialization messages, you should see:&lt;br /&gt;
&lt;code&gt;The sum of 123 and 456 is: 579&lt;/code&gt;&lt;br /&gt;
as the result of executing the JavaScript code from &lt;code&gt;app.js&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note: &lt;/strong&gt; the JavaScript code MUST be in a file named &lt;code&gt;app.js&lt;/code&gt;, and you can&#039;t just use any filename you like, because after booting, the firmware runtime looks for this specific file, and if is found, the JavaScript code is executed. Note that if you have JavaScript errors in your code, the module may behave strange, like continuously resetting itself, and in some cases, the only way to have it back working is to upload the firmware again!&lt;/p&gt;

&lt;p&gt;You may also want to check this &lt;a href=&quot;https://www.youtube.com/watch?v=kThcRN8VF0Q&quot;&gt;YouTube&lt;/a&gt; video showing the basics steps in using the &lt;a href=&quot;https://mongoose-iot.com/&quot;&gt;Mongoose-IoT Cloud Service&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;buildFirmwareRPi&quot;&gt;Build and Flash Mongoose-IoT ESP8266 Firmware by Using a Raspberry Pi Board&lt;/h2&gt;

&lt;p&gt;Since we like to add more functionality into the existing Mongoose-IoT firmware, discussed later in this article, we need to compile the firmware and flash it to the ESP module. For this, we need to prepare our system by following the steps below:&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;install docker, if not already existing in your system:&lt;br /&gt;
	&lt;code class=&quot;consoleCode&quot;&gt;# sudo curl -sSL https://get.docker.com | sh&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;allow user to use docker (add user to docker group):&lt;br /&gt;
	&lt;code class=&quot;consoleCode&quot;&gt;sudo usermod -aG docker pi&lt;/code&gt;&lt;br /&gt;
	Notice that we have used the user with name &lt;code&gt;pi&lt;/code&gt; in the example above, if is the case, replace this accordingl&lt;/li&gt;
	&lt;li&gt;start the docker service:&lt;br /&gt;
	&lt;code class=&quot;consoleCode&quot;&gt;# sudo systemctl daemon-reload&lt;br /&gt;
	&lt;br /&gt;
	# sudo service docker start &lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;clone the git repository of the &lt;a href=&quot;https://github.com/cesanta/mongoose-iot&quot;&gt;Mongoose-IoT Firmware&lt;/a&gt; project:&lt;br /&gt;
	&lt;code class=&quot;consoleCode&quot;&gt;# git clone https://github.com/cesanta/mongoose-iot&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;enter the ESP8266 firmware project folder:&lt;br /&gt;
	&lt;code class=&quot;consoleCode&quot;&gt;# cd mongoose-iot/fw/platforms/esp8266&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;edit the Makefile.build and make sure that the following parameters are set:
	&lt;pre&gt;
APP_FS_PATH ?= $(REPO_PATH)/fw/platforms/esp8266/fs
MG_ENABLE_JS ?= 0
CREATE_RAW_FS ?= 1&lt;/pre&gt;
	&lt;/li&gt;
	&lt;li&gt;build the firmware:&lt;br /&gt;
	&lt;code class=&quot;consoleCode&quot;&gt;# sudo make&lt;/code&gt;&lt;br /&gt;
	Notice that this task may take some time to complete, for the first time, since various &lt;code&gt;docker&lt;/code&gt; image packages needs to be downloaded and extracted on your machine&lt;/li&gt;
	&lt;li&gt;when the build process is complete, the resulting firmware zip archive file is: &lt;code&gt;mongoose-iot/fw/platforms/esp8266/firmware/mongoose-iot-esp8266-last.zip&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;open the MFT application in advanced mode, by executing:&lt;br /&gt;
	&lt;code class=&quot;consoleCode&quot;&gt;./MFT --advanced &lt;/code&gt;&lt;br /&gt;
	from the &lt;code&gt;mongoose-flashing-tool/src&lt;/code&gt; folder&lt;/li&gt;
	&lt;li&gt;connect to the ESP module by using the &lt;code&gt;connect&lt;/code&gt; button, after selecting the correct communication port (e.g., &lt;code&gt;ttyUSB0&lt;/code&gt;), then use the &lt;code&gt;Firmwware&lt;/code&gt; section to select the firmware zip file created above, and press the &lt;code&gt;Flash&lt;/code&gt; button&lt;/li&gt;
	&lt;li&gt;in a few seconds, the flash process must be completed, now reboot the ESP module by clicking the &lt;code&gt;Reboot&lt;/code&gt; button&lt;/li&gt;
	&lt;li&gt;test if the module works as expected: execute &lt;code&gt;Sys.conf&lt;/code&gt; in the MFT console, and you should see current configuration settings.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can also download the &quot;ready to flash&quot; Mongoose-IoT Firmware for ESP8266 with DHT11/21/22 JavaScript support by using the download button below:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://web-engineering.info/sites/default/files/wot_tutorials/Mongoose-IoT-ESP8266/mongoose-iot-esp8266-firmware.zip&quot; style=&quot;padding: 
2px 3px; margin: 1em; border: 1px solid black;&quot;&gt;Download Mongoose-IoT Firmware for ESP8266 with DHT11/21/22 JavaScript Support&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Expose Custom JavaScript Global Methods and Objects&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Note: &lt;/strong&gt;the complete source code for all the examples discussed in this section is available on our &lt;a href=&quot;https://github.com/dimircea/MongooseIoT-Extensions/tree/master/DHTxx&quot;&gt;GitHub&lt;/a&gt; project page. You can also download the code using the links from this article, however, it may be outdated after some time, so we strongly recommend our &lt;a href=&quot;https://github.com/dimircea/MongooseIoT-Extensions/tree/master/DHTxx&quot;&gt;GitHub&lt;/a&gt; project page instead.&lt;/p&gt;

&lt;p&gt;Some components, such as &lt;a href=&quot;http://web-engineering.info/sites/default/files/wot_tutorials/Mongoose-IoT-ESP8266/DHT22_AM2302.pdf&quot;&gt;DHT22 / AM2302&lt;/a&gt;, temperature and humidity sensor, but not only, are harder to be read directly from the JavaScript code with the Mongoose-IoT firmware. This happens because the MCU is simply not fast enough for the JavaScript interpreter, so we can&#039;t deal with the very small pulses (under 20μs) we need to measure on the code, for being able to communicate with such components. The alternative and better approach is to write custom C/C++ code as part of the Mongoose-IoT firmware, and expose some objects and methods to JavaScript, thus being executed by the native firmware code, which is so much faster.&lt;/p&gt;

&lt;p&gt;First we define a flag which allows to enable of disable the DHTxx library, so in case that for a project you don&#039;t need such a sensor, is possible to exclude this code from the firmware simply by using a flag. Notice that the firmware needs to be compiled/rebuild after adding or dropping the parameter. The following C/C++ code is part of the &lt;code&gt;fw/platforms/esp8266/user/v7_esp_features.h&lt;/code&gt; file:&lt;/p&gt;

&lt;pre&gt;
#ifndef CS_FW_PLATFORMS_ESP8266_USER_V7_ESP_FEATURES_H_
  #define CS_FW_PLATFORMS_ESP8266_USER_V7_ESP_FEATURES_H_
  &lt;strong&gt;#define V7_ESP_ENABLE__DHT&lt;/strong&gt;
#endif 
&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Note: &lt;/strong&gt; only the marked code line is new (added by us), the rest of the code already exists as part of the &lt;code&gt;fw/platforms/esp8266/user/v7_esp_features.h&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;The next step is to modify the file &lt;code&gt;fw/platforms/esp8266/user/v7_esp.c&lt;/code&gt; by considering the code shown below:&lt;/p&gt;

&lt;pre&gt;
&lt;strong&gt;#include &quot;fw/platforms/esp8266/user/dht.h&quot;&lt;/strong&gt;

&lt;strong&gt;#ifdef V7_ESP_ENABLE__DHT&lt;/strong&gt;
  static enum v7_err DHT_read(struct v7 *v7, v7_val_t *result) {
    v7_val_t sensorTypeArg = v7_arg(v7, 0);
    v7_val_t pinArg = v7_arg(v7, 1);
  
    // validate the first parameter - the DHT sensor type (11, 21, or 22)
    if (!v7_is_number(sensorTypeArg) || 
        (v7_get_double(v7, sensorTypeArg) != 1 
        &amp;amp;&amp;amp; v7_get_double(v7, sensorTypeArg) != 2 
        &amp;amp;&amp;amp; v7_get_double(v7, sensorTypeArg) != 3)) 
      return v7_throwf(v7, &quot;Error&quot;, &quot;Parameter 1, must be one of Dht.TypeEL.DHTxx.&quot;);

    // validate the second parameter - the GPIO pin number
    &lt;strong&gt;if (!v7_is_number(pinArg)) 
      return v7_throwf(v7, &quot;Error&quot;, &quot;Parameter 2, must be a GPIO pin number.&quot;);&lt;/strong&gt;

    uint8_t pin = v7_get_int(v7, pinArg);
    uint8_t sType = v7_get_int(v7, sensorTypeArg);
    double temperature = 0.0;
    double humidity = 0.0;
    const char* sTypeName = (sType == 1 ? &quot;DHT11&quot; : (sType == 2 ? &quot;DHT21&quot; : &quot;DHT22&quot;));

    // read the DHT sensor and check if the read was a successful
    if (&lt;strong&gt;!dhtRead(sType, pin, &amp;amp;temperature, &amp;amp;humidity)&lt;/strong&gt;) {
      // error reading DHT sensor...normally this is a check sum error
      return v7_throwf(v7, &quot;Error&quot;, &quot;Failed to read the DHT sensor!&quot;);
    }
    
    // create the result JavaScript object and append the 
    // &quot;type&quot;, &quot;temperature&quot; and &quot;humidity&quot; properties, as well as their values
    &lt;strong&gt;*result = v7_mk_object(v7);
    v7_set(v7, *result, &quot;type&quot;, 4, v7_mk_string(v7, sTypeName, 5, 1));
    v7_set(v7, *result, &quot;temperature&quot;, 11, v7_mk_number(v7, temperature));
    v7_set(v7, *result, &quot;humidity&quot;, 8, v7_mk_number(v7, humidity));
    return V7_OK;&lt;/strong&gt;
  };
#endif /* V7_ESP_ENABLE__DHT */
&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;DHT_read&lt;/code&gt; method is responsible to check the parameters provided to the JavaScript &lt;code&gt;Dht.read&lt;/code&gt; method. Internally, the &lt;code&gt;dhtRead&lt;/code&gt; method will be called - it is responsible for the communication with the sensor, as discussed further in this section. Finally, a JavaScript anonymous object representing the JavaScript &lt;code&gt;Dht.read&lt;/code&gt; method response is created. It is stored in a pointer, the last parameter of the &lt;code&gt;DHT_read&lt;/code&gt; method. Notice that the &lt;code&gt;DHT_read&lt;/code&gt; method returns &lt;code&gt;V7_OK&lt;/code&gt; or throws exceptions, depending on the case. Also notice that &lt;code&gt;DHT_read&lt;/code&gt; is a name that we choose, so you are free to change it with whatever you find appropriate, but remember to change every reference in the code.&lt;/p&gt;

&lt;p&gt;Further, in the same &lt;code&gt;fw/platforms/esp8266/user/v7_esp.c&lt;/code&gt; file, we modify the &lt;code&gt;init_v7&lt;/code&gt; method code as shown below:&lt;/p&gt;

&lt;pre&gt;
&lt;strong&gt;void init_v7( void *stack_base)&lt;/strong&gt; {
  // this code is compiled and becomes part of the firmware, only if the 
  // V7_ESP_ENABLE__DHT flag is used
  &lt;strong&gt;#ifdef V7_ESP_ENABLE__DHT&lt;/strong&gt;
    v7_val_t dht = v7_mk_object(v7);
    v7_val_t typeEL = v7_mk_object(v7);
    // create the Dht global object, accessible in JS code
    &lt;strong&gt;v7_set(v7, v7_get_global(v7), &quot;Dht&quot;, 3, dht);&lt;/strong&gt;
    // add the read method to the DHT JS object
    &lt;strong&gt;v7_set_method(v7, dht, &quot;read&quot;, DHT_read);&lt;/strong&gt;
    // define the Dht.TypeEL enumeration property
    &lt;strong&gt;v7_def(v7, dht, &quot;TypeEL&quot;, 6, 
      (V7_DESC_WRITABLE(0) | V7_DESC_ENUMERABLE(1)), typeEL);&lt;/strong&gt;
    // create the Dht.TypeEL.DHT11 enumeration literal 
    // {enumerable: true, writable: false}
    &lt;strong&gt;v7_def(v7, typeEL, &quot;DHT11&quot;, 5, 
      (V7_DESC_WRITABLE(0) | V7_DESC_ENUMERABLE(1)), v7_mk_number(v7, 1));&lt;/strong&gt;
    // create the Dht.TypeEL.DHT21 enumeration literal 
    // {enumerable: true, writable: false}
    v7_def(v7, typeEL, &quot;DHT21&quot;, 5, 
      (V7_DESC_WRITABLE(0) | V7_DESC_ENUMERABLE(1)), v7_mk_number(v7, 2));
    // create the Dht.TypeEL.DHT22 enumeration literal 
    // {enumerable: true, writable: false}
    v7_def(v7, typeEL, &quot;DHT22&quot;, 5, 
      (V7_DESC_WRITABLE(0) | V7_DESC_ENUMERABLE(1)), v7_mk_number(v7, 3));
  #endif /* V7_ESP_ENABLE__DHT */
}
&lt;/pre&gt;

&lt;p&gt;The purpose of this code is to create the &lt;code&gt;Dht&lt;/code&gt; JavaScript object (accessible from the JavaScript code running on the ESP module), create the &lt;code&gt;Dht.TypeEL&lt;/code&gt; JavaScript &quot;enumeration&quot; (well, emulating an enumeration) and to expose the &lt;code&gt;Dht.read&lt;/code&gt; method, so we are able to read the DHT sensor from a JavaScript program.&lt;/p&gt;

&lt;p&gt;Notice that we can create objects and object properties for the exposed JavaScript interface, in a similar manner as we do in standard JavaScript code with the help of &lt;code&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty&quot;&gt;Object.defineProperty&lt;/a&gt;&lt;/code&gt; and &lt;code&gt;&lt;a href=&quot;https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties&quot;&gt;Object.defineProperties&lt;/a&gt;&lt;/code&gt;, thus we can make a property read-only, enumerable and provide an initial value to it if required. Datatypes values are obtained by calling the corresponding &lt;code&gt;v7_mk_xxx&lt;/code&gt; method, where &lt;code&gt;xxx&lt;/code&gt; can be &lt;code&gt;null&lt;/code&gt;, &lt;code&gt;object&lt;/code&gt;, &lt;code&gt;number&lt;/code&gt; or &lt;code&gt;string&lt;/code&gt; depending on the case.&lt;/p&gt;

&lt;p&gt;It is also important to know that when we use the &lt;code&gt;v7_def&lt;/code&gt; and &lt;code&gt;v7_set&lt;/code&gt; methods, their 4th parameter is a positive integer, representing the number of characters of the name of the property or method that is created. Failing to set this value correctly, results in the property or method not being recognized in the JavaScript code!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note: &lt;/strong&gt; the init_v7 method contains additional code, which should be kept unchanged. In this tutorial only show the new code, required for our custom functionality, but the existing code must not be changed, otherwise the resulting firmware may not work as expected.&lt;/p&gt;

&lt;p&gt;Now, we need to write the a C/C++ header file that exposes the method(s) meant to be used by the Mongoose-IoT firmware for the communication with the DHTxx sensor. We create the file &lt;code&gt;fw/platforms/esp8266/user/dht.h&lt;/code&gt; that defines the signature of the &lt;code&gt;dhtRead&lt;/code&gt; method:&lt;/p&gt;

&lt;pre&gt;
#ifndef DHT_LIBRARY
  #define DHT_LIBRARY
  #include &quot;v7_esp_features.h&quot;

  #ifdef V7_ESP_ENABLE__DHT
   &lt;strong&gt;bool dhtRead(uint8_t sensorType, uint8_t pin, double* temperature, double* humidity);&lt;/strong&gt;
  #endif
#endif&lt;/pre&gt;

&lt;p&gt;Notice that this header file was already used in the &lt;code&gt;fw/platforms/esp8266/user/v7_esp.c&lt;/code&gt; code. Finally, we need to add the &lt;code&gt;fw/platforms/esp8266/user/dht.c&lt;/code&gt; file, where we put the code that allows us to communicate with any of the the DHT11/21/22 sensors, for getting temperature and humidity readings:&lt;/p&gt;

&lt;pre&gt;
#include &amp;lt;osapi.h&amp;gt;
#include &quot;v7/v7.h&quot;
#include &quot;common/platforms/esp8266/esp_missing_includes.h&quot;
#include &quot;fw/platforms/esp8266/user/v7_esp_features.h&quot;
&lt;strong&gt;#include &quot;fw/platforms/esp8266/user/util.h&quot;
#include &quot;fw/platforms/esp8266/user/esp_gpio.h&quot;&lt;/strong&gt;

#ifdef V7_ESP_ENABLE__DHT
  &lt;strong&gt;static uint16_t waitLHCycle(uint8_t pin, uint32_t* maxCycles)&lt;/strong&gt; {
    // wait until the pin goes from a digital LOW state 
    // to a digital HIGH state, or until the timeout occurs
    // NOTE: this is a helper method for dhtReadByte, to avoid repetitive code
  };
  &lt;strong&gt;static uint8_t dhtReadByte(uint8_t pin, uint32_t* maxCycles)&lt;/strong&gt; {
    // read one byte (8 bits) of data from the DHTxx sensor
    // by using the sensor datasheet which explains what means a bit 1 and a bit 0
  };
  &lt;strong&gt;bool dhtRead(uint8_t sensorType, uint8_t pin, double* temperature, double* humidity)&lt;/strong&gt; {
    // 1) read the 5 bytes of data from the DHTxx sensor;
    // 2) perform a check sum test for data integrity (the 5th byte is the check sum one);
    // 3) decode the 4 bytes of data and transform them to temperature and humidity values
  };
#endif&lt;/pre&gt;

&lt;p&gt;See the &lt;a href=&quot;https://github.com/dimircea/MongooseIoT-Extensions/blob/master/DHTxx/src/dht.c&quot;&gt;fw/platforms/esp8266/user/dht.c&lt;/a&gt; full source code on GitHub or download the full source code archive using the link at the top of this tutorial page.&lt;/p&gt;

&lt;p&gt;Lets have a look at the interesting parts only, mainly how to control GPIO pins. Before being able to interact with a GPIO pin, we need to set the pin either for read of write mode, with the help of &lt;code&gt;mg_gpio_set_mode&lt;/code&gt; method. It accepts three parameters: 1) the GPIO pin number; (e.g., 5 for GPIO5) 2) the mode, which is one of &lt;code&gt;{GPIO_MODE_INOUT = 0, GPIO_MODE_INPUT = 1, GPIO_MODE_OUTPUT = 2}&lt;/code&gt;; 3) GPIO pull type, one of &lt;code&gt;{GPIO_PULL_FLOAT = 0, GPIO_PULL_PULLUP = 1, GPIO_PULL_PULLDOWN = 2}&lt;/code&gt;, specifying if the GPIO pin is internally pulled up, down or let floating. The following example makes sets the GPIO5 pin as a digital output and GPIO4 as pulled down digital input:&lt;/p&gt;

&lt;pre&gt;
mg_gpio_set_mode( 5, GPIO_MODE_OUTPUT, GPIO_PULL_FLOAT);
mg_gpio_set_mode( 4, GPIO_MODE_INPUT, GPIO_PULL_DOWN);&lt;/pre&gt;

&lt;p&gt;Reading the state of a digital pin that was set as digital input is made by using &lt;code&gt;read_gpio_pin&lt;/code&gt; method, which returns &lt;code&gt;GPIO_LEVEL_ERR&lt;/code&gt; (&lt;code&gt;GPIO_LEVEL_ERR = -1&lt;/code&gt;) in case of error, &lt;code&gt;GPIO_LEVEL_LOW&lt;/code&gt; (&lt;code&gt;GPIO_LEVEL_LOW = 0&lt;/code&gt;) if a LOW status was read and &lt;code&gt;GPIO_LEVEL_HIGH&lt;/code&gt; (&lt;code&gt;GPIO_LEVEL_HIGH = 1&lt;/code&gt;) if a HIGH state was read. To set the status of a GPIO that was set as output implies to use the &lt;code&gt;set_gpio method&lt;/code&gt;, which takes two parameters: 1) the GPIO pin number (e.g., 5 for GPIO5); 2) the state to set the pin to, one of &lt;code&gt;{GPIO_LEVEL_LOW = 0, GPIO_LEVEL_HIGH = 1}&lt;/code&gt;. For example, if we like to wait for a HIGH signal on GPIO4 pin (set as digital input in the above example) and write a HIGH state on GPIO5 (set as digital output in the above example) afterwards, we&#039;ll use:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;
while( read_gpio_pin( 5) == GPIO_LEVEL_LOW);
set_gpio( 4, GPIO_LEVEL_HIGH);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Note: &lt;/strong&gt; the following two header files are required for getting the above described GPIO operations: &lt;code&gt;fw/platforms/esp8266/user/util.h&lt;/code&gt; and &lt;code&gt;fw/platforms/esp8266/user/esp_gpio.h&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To make this new feature available on your ESP module, you&#039;ll need to compile and build the source code, then flash the firmware, as shown in &lt;a href=&quot;#buildFirmwareRPi&quot;&gt;Section: Build the Mongoose-IoT Firmware on a Raspberry Pi&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After uploading the new firmware, test the DHT functionality by using the following JavaScript code in the MFT Console, or as part of the &lt;code&gt;app.js&lt;/code&gt; file:&lt;/p&gt;

&lt;pre&gt;
Dht.read( Dht.TypeEL.DHT11, 5);
&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Note: &lt;/strong&gt;if is the case, replace &lt;code&gt;Dht.TypeEL.DHT11&lt;/code&gt; with &lt;code&gt;Dht.TypeEL.DHT21&lt;/code&gt; or &lt;code&gt;Dht.TypeEL.DHT22&lt;/code&gt;, depending on the used DHT sensor type, and also replace 5 (the second parameter) with the corresponding GPIO number, to which you have connected the data pin of the DHT sensor.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://web-engineering.info/sites/default/files/wot_tutorials/Mongoose-IoT-ESP8266/DHTxx_src.zip&quot; style=&quot;padding: 
2px 3px; margin-removed 1em; border: 1px solid black;&quot;&gt;Download the code&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;The ESP8266&#039;s Big Brother: ESP32&lt;/h2&gt;

&lt;p&gt;The ESP8266 module got lately a big brother: the new ESP32 module. It is more powerful, but also comes with new features, such as builtin Bluetooth 4.2. In &lt;a href=&quot;#fig13&quot;&gt;Figure 13&lt;/a&gt; we can see the official ESP32 modules, also named &lt;a href=&quot;http://www.pighixxx.com/test/2016/08/wroom32/&quot;&gt;WROOM-32&lt;/a&gt;. The following table provides the main differences of ESP32 by comparison with ESP8266.&lt;/p&gt;

&lt;table&gt;
	&lt;thead&gt;
		&lt;tr&gt;
			&lt;th&gt;Feature / Component&lt;/th&gt;
			&lt;th&gt;ESP8266&lt;/th&gt;
			&lt;th&gt;ESP32&lt;/th&gt;
		&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
		&lt;tr&gt;
			&lt;td&gt;MCU&lt;/td&gt;
			&lt;td&gt;Xtensa Single-Core 32-bit L106, 80MHz&lt;/td&gt;
			&lt;td&gt;&amp;gt;Xtensa Dual-Core 32-bit LX6, 160MHz&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;RAM&lt;/td&gt;
			&lt;td&gt;160KB&lt;/td&gt;
			&lt;td&gt;512KB&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;FLASH&lt;/td&gt;
			&lt;td&gt;up to 16MB SPI Flash&lt;/td&gt;
			&lt;td&gt;up to 16MB SPI Flash&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;GPIOs&lt;/td&gt;
			&lt;td&gt;17&lt;/td&gt;
			&lt;td&gt;36&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;SPI/I2C/I2S/UART/CAN&lt;/td&gt;
			&lt;td&gt;2/1/2/2/0&lt;/td&gt;
			&lt;td&gt;4/2/2/2/1&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;ADC&lt;/td&gt;
			&lt;td&gt;1 x 10bits&lt;/td&gt;
			&lt;td&gt;1 x 12bits&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;WiFi&lt;/td&gt;
			&lt;td&gt;b/g/n, HT20&lt;/td&gt;
			&lt;td&gt;b/g/n, HT40&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;Bluetooth&lt;/td&gt;
			&lt;td&gt;-&lt;/td&gt;
			&lt;td&gt;v4.2&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;Builtin sensors&lt;/td&gt;
			&lt;td&gt;-&lt;/td&gt;
			&lt;td&gt;temperature, touch&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;Working conditions&lt;/td&gt;
			&lt;td&gt;-40°C - 125°C&lt;/td&gt;
			&lt;td&gt;-40°C - 125°C&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;Approximate price&lt;/td&gt;
			&lt;td&gt;3-10 EUR, including shipping to EU&lt;/td&gt;
			&lt;td&gt;10-22 EUR, including shipping to EU&lt;/td&gt;
		&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;

&lt;figure id=&quot;fig13&quot;&gt;&lt;a href=&quot;http://web-engineering.info/sites/default/files/wot_tutorials/Mongoose-IoT-ESP8266/esp32_wroom.png&quot;&gt;&lt;img alt=&quot;WROOM-32, the Official ESP32 Module&quot; src=&quot;http://web-engineering.info/sites/default/files/wot_tutorials/Mongoose-IoT-ESP8266/esp32_wroom.png&quot; /&gt;&lt;/a&gt;

&lt;figcaption&gt;Figure 13: WROOM-32, the Official ESP32 Module.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Unfortunately, at the moment of writing this tutorial, it is not easy to buy the ESP32 module, since most of the online sources (the vast majority from Asia) report the module as &quot;out of stock&quot;. However, we strongly believe that the situation will change soon, and the ESP32 may take the place of ESP8266 modules in new projects, or as improvements of the old projects that requires WiFi or Bluetooth connection and MCU on a single small and cheap module.&lt;/p&gt;

&lt;h2&gt;Some Points of Attention&lt;/h2&gt;

&lt;p&gt;The ESP8266 module represents the brain of your projects, but it requires that you take some precautions to keep it safe and be sure that it runs as supposed:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Most of the ESP8266 modules are powered by 3.3V, thus using 5V or anything more than 3.6V may and will damage your module! Some of the ESP8266 modules, such as the NodeMCU or WeMOS, discussed in this article, allows to power the module board (but not directly the ESP8266 MCU!) by using a USB connector (mini or micro USB ones), thus using 5V (or up to 10V for WeMOS D1 Mini), while a builtin voltage regulator is responsible for converting this down to 3.3V as required by the MCU.&lt;/li&gt;
	&lt;li&gt;No matter the input voltage accepted by an ESP8266 module (usually a direct 3.3V input or 5V via USB connector), in most cases the GPIOs pins are tolerant to ONL 3.3V or less positive voltage, meaning that you should never ever provide more than 3.3V nor a negative voltage to any of the GPIO pins.&lt;/li&gt;
	&lt;li&gt;The ESP8266 module exposes one ADC pin (expandable by using multiplexing or specialized ICs), allowing to measure analog voltages in the range 0-1V. Do NOT provide more than 1V or a negative voltage to this pin. If more than 1V must be measured, then use a &lt;a href=&quot;https://en.wikipedia.org/wiki/Voltage_divider&quot;&gt;voltage divider circuit&lt;/a&gt; or an external ADC IC or module (e.g., &lt;a href=&quot;https://www.adafruit.com/product/1083&quot;&gt;ADS1015 12-Bit ADC - 4 Channel&lt;/a&gt;) capable to communicate via I2C, SPI or UART. However, some modules, such as WeMOS D1 Mini allows 0-3.3V as input for the ADC pin, since it uses a builtin voltage divider circuit.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;section class=&quot;field field-name-field-category field-type-taxonomy-term-reference field-label-above view-mode-rss&quot;&gt;&lt;h2 class=&quot;field-label&quot;&gt;Category:&amp;nbsp;&lt;/h2&gt;&lt;ul class=&quot;field-items&quot;&gt;&lt;li class=&quot;field-item even&quot;&gt;&lt;a href=&quot;/taxonomy/term/40&quot; typeof=&quot;skos:Concept&quot; property=&quot;rdfs:label skos:prefLabel&quot; datatype=&quot;&quot;&gt;WoT&lt;/a&gt;&lt;/li&gt;&lt;li class=&quot;field-item odd&quot;&gt;&lt;a href=&quot;/taxonomy/term/50&quot; typeof=&quot;skos:Concept&quot; property=&quot;rdfs:label skos:prefLabel&quot; datatype=&quot;&quot;&gt;IoT&lt;/a&gt;&lt;/li&gt;&lt;li class=&quot;field-item even&quot;&gt;&lt;a href=&quot;/JavaScript&quot; typeof=&quot;skos:Concept&quot; property=&quot;rdfs:label skos:prefLabel&quot; datatype=&quot;&quot;&gt;JavaScript&lt;/a&gt;&lt;/li&gt;&lt;li class=&quot;field-item odd&quot;&gt;&lt;a href=&quot;/taxonomy/term/51&quot; typeof=&quot;skos:Concept&quot; property=&quot;rdfs:label skos:prefLabel&quot; datatype=&quot;&quot;&gt;ESP8266&lt;/a&gt;&lt;/li&gt;&lt;li class=&quot;field-item even&quot;&gt;&lt;a href=&quot;/taxonomy/term/52&quot; typeof=&quot;skos:Concept&quot; property=&quot;rdfs:label skos:prefLabel&quot; datatype=&quot;&quot;&gt;WiFi&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/section&gt;&lt;div class=&quot;easy_social_box clearfix horizontal easy_social_lang_und&quot;&gt;
            &lt;div class=&quot;easy_social-widget easy_social-widget-twitter first&quot;&gt;&lt;a href=&quot;http://twitter.com/share&quot; class=&quot;twitter-share-button&quot;
data-url=&quot;https://web-engineering.info/node/65&quot;
data-count=&quot;horizontal&quot;
data-lang = &quot;en&quot;
data-via=&quot;&quot;
data-related=&quot;:Check it out!&quot;
data-text=&quot;JavaScript-Based IoT/WoT Development with the ESP8266 and the Raspberry Pi&quot;&gt;Tweet&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&quot;easy_social-widget easy_social-widget-facebook&quot;&gt;&lt;fb:like href=&quot;https://web-engineering.info/node/65&quot; send=&quot;true&quot; layout=&quot;button_count&quot; width=&quot;88&quot; show_faces=&quot;true&quot; action=&quot;like&quot; colorscheme=&quot;light&quot; font=&quot;&quot;&gt;&lt;/fb:like&gt;&lt;/div&gt;
          &lt;div class=&quot;easy_social-widget easy_social-widget-googleplus&quot;&gt;&lt;div class=&quot;g-plusone&quot; data-size=&quot;medium&quot; data-annotation=&quot;bubble&quot; data-href=&quot;https://web-engineering.info/node/65&quot;&gt;&lt;/div&gt;&lt;/div&gt;
          &lt;div class=&quot;easy_social-widget easy_social-widget-linkedin last&quot;&gt;&lt;script type=&quot;in/share&quot; data-url=&quot;https://web-engineering.info/node/65&quot; data-counter=&quot;right&quot;&gt;&lt;/script&gt;&lt;/div&gt;
  &lt;/div&gt; &lt;!-- /.easy_social_box --&gt;</description>
 <pubDate>Wed, 21 Sep 2016 09:52:01 +0000</pubDate>
 <dc:creator>mdiaconescu</dc:creator>
 <guid isPermaLink="false">65 at https://web-engineering.info</guid>
 <comments>https://web-engineering.info/node/65#comments</comments>
</item>
<item>
 <title>Web Development Pitfall No.1: Confusing a DOM collection with a JS array</title>
 <link>https://web-engineering.info/node/49</link>
 <description>&lt;div class=&quot;field field-name-body field-type-text-with-summary field-label-hidden view-mode-rss&quot;&gt;&lt;div class=&quot;field-items&quot;&gt;&lt;div class=&quot;field-item even&quot; property=&quot;content:encoded&quot;&gt;&lt;h2&gt;Summary&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Don&#039;t confuse a DOM collection with a JS array: Array functions, such as the &lt;code&gt;forEach&lt;/code&gt; looping method, cannot be applied to a DOM collection!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For instance, when you retrieve all rows of an HTML table element, you get an &lt;code&gt;HTMLCollection&lt;/code&gt;, which is an array-like object, but not an instance of &lt;code&gt;Array&lt;/code&gt;, and therefore the following code does not succeed because the &lt;code&gt;Array&lt;/code&gt; method &lt;code&gt;forEach&lt;/code&gt; is not defined for an &lt;code&gt;HTMLCollection&lt;/code&gt; like &lt;code&gt;myTableEl.rows&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;
var myTableEl = document.getElementById(&quot;myTableEl&quot;);
myTableEl.rows.forEach( function (row) {
  ... // process row
})&lt;/pre&gt;

&lt;p&gt;There are two solutions how to loop over a DOM collection like &lt;code&gt;myTableEl.rows&lt;/code&gt;. Either by using an ordinary for loop, like so:&lt;/p&gt;

&lt;pre&gt;
var myTableEl = document.getElementById(&quot;myTableEl&quot;);
var i=0, row=null;
for (i=0; i &amp;lt; myTableEl.rows.length; i++) {
  row = myTableEl.rows[i];
  ... // process row
}&lt;/pre&gt;

&lt;p&gt;or by invoking the &lt;code&gt;Array&lt;/code&gt; method &lt;code&gt;forEach&lt;/code&gt; on the DOM collection with the help of &lt;code&gt;call&lt;/code&gt; in the following way:&lt;/p&gt;

&lt;pre&gt;
var myTableEl = document.getElementById(&quot;myTableEl&quot;);
Array.prototype.forEach.call( myTableEl.rows, function (row) {
  ... // process row
})&lt;/pre&gt;

&lt;h2&gt;More on DOM Collections&lt;/h2&gt;

&lt;p&gt;Mozilla provides a pretty good &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model&quot;&gt;overview of DOM interfaces&lt;/a&gt;, though not all methods have proper documentation yet. The ultimate reference is, of course, the hard-to-digest DOM4 specification, which comes in two forms: the &lt;a href=&quot;http://www.w3.org/TR/dom/&quot;&gt;W3C DOM4 spec&lt;/a&gt; and the&amp;nbsp; WHATWG&#039;s &lt;a href=&quot;https://dom.spec.whatwg.org/&quot;&gt;&lt;span class=&quot;content&quot;&gt;DOM Living Standard&lt;/span&gt;&lt;/a&gt;&lt;span class=&quot;content&quot;&gt;.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;A DOM collection is an array-like object &lt;code&gt;coll&lt;/code&gt;, the items of which can be accessed with the array index notation &lt;code&gt;coll[i],&lt;/code&gt; and that has a &lt;code&gt;length&lt;/code&gt; attribute such that a for loop can be used for iterating over it. There are 4 different types of DOM collections:&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;The most important one, &lt;code&gt;HTMLCollection&lt;/code&gt;, represents a collection of HTML elements, typically obtained by retrieving HTML elements with one of the methods &lt;code&gt;getElementsByTagName&lt;/code&gt;, &lt;code&gt;getElementsByClassName&lt;/code&gt; or &lt;code&gt;querySelectorAll&lt;/code&gt;.&lt;/li&gt;
	&lt;li&gt;A &lt;code&gt;DOMTokenList&lt;/code&gt; represents a collection of items of an HTML attribute value list, such as the values of the HTML &lt;code&gt;class&lt;/code&gt; attribute.&lt;/li&gt;
	&lt;li&gt;A &lt;code&gt;NamedNodeMap&lt;/code&gt; represents a collection of attributes (notice that, despite the historical name of this DOM collection type, attributes are no longer considered to be nodes in DOM4).&lt;/li&gt;
	&lt;li&gt;A &lt;code&gt;NodeList&lt;/code&gt; represents a collection of DOM nodes, which may be elements, plain text, comments or processing instructions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All of these DOM collections have the &lt;code&gt;item&lt;/code&gt; method in common, which implies that their items can be accessed with the array index notation. Two of them,&amp;nbsp;&lt;code&gt;HTMLCollection&lt;/code&gt; and &lt;code&gt;NamedNodeMap&lt;/code&gt;, also have a (get)&lt;code&gt;namedItem&lt;/code&gt; method, which implies that their items can be accessd with the key-value map notation. In the case of an &lt;code&gt;HTMLCollection&lt;/code&gt;, the keys are provided by the elements&#039; &lt;code&gt;id&lt;/code&gt; attribute, while in the case of a &lt;code&gt;NamedNodeMap&lt;/code&gt;, the keys are provided by the attribute names.&lt;/p&gt;

&lt;p&gt;This is summarized in the following UML class diagram.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;data:image/png;base64,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&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Notice that a DOM element is a special type of DOM node (as expressed by the UML generalization arrow), so we can also use the attribute &lt;code&gt;childNodes&lt;/code&gt; for an HTML element or SVG element for collecting all child nodes of it in the form of a &lt;code&gt;NodeList&lt;/code&gt;, including child&amp;nbsp;elements, but also comments, processing instructions, etc. However, when you only need to retrieve child elements, such as all child elements of a certain &lt;code&gt;div&lt;/code&gt;, then you better use the method &lt;code&gt;children&lt;/code&gt;, whcih returns an &lt;code&gt;HTMLCollection&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;section class=&quot;field field-name-field-category field-type-taxonomy-term-reference field-label-above view-mode-rss&quot;&gt;&lt;h2 class=&quot;field-label&quot;&gt;Category:&amp;nbsp;&lt;/h2&gt;&lt;ul class=&quot;field-items&quot;&gt;&lt;li class=&quot;field-item even&quot;&gt;&lt;a href=&quot;/JavaScript&quot; typeof=&quot;skos:Concept&quot; property=&quot;rdfs:label skos:prefLabel&quot; datatype=&quot;&quot;&gt;JavaScript&lt;/a&gt;&lt;/li&gt;&lt;li class=&quot;field-item odd&quot;&gt;&lt;a href=&quot;/DOM&quot; typeof=&quot;skos:Concept&quot; property=&quot;rdfs:label skos:prefLabel&quot; datatype=&quot;&quot;&gt;DOM&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/section&gt;&lt;div class=&quot;easy_social_box clearfix horizontal easy_social_lang_und&quot;&gt;
            &lt;div class=&quot;easy_social-widget easy_social-widget-twitter first&quot;&gt;&lt;a href=&quot;http://twitter.com/share&quot; class=&quot;twitter-share-button&quot;
data-url=&quot;https://web-engineering.info/node/49&quot;
data-count=&quot;horizontal&quot;
data-lang = &quot;en&quot;
data-via=&quot;&quot;
data-related=&quot;:Check it out!&quot;
data-text=&quot;Web Development Pitfall No.1: Confusing a DOM collection with a JS array&quot;&gt;Tweet&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&quot;easy_social-widget easy_social-widget-facebook&quot;&gt;&lt;fb:like href=&quot;https://web-engineering.info/node/49&quot; send=&quot;true&quot; layout=&quot;button_count&quot; width=&quot;88&quot; show_faces=&quot;true&quot; action=&quot;like&quot; colorscheme=&quot;light&quot; font=&quot;&quot;&gt;&lt;/fb:like&gt;&lt;/div&gt;
          &lt;div class=&quot;easy_social-widget easy_social-widget-googleplus&quot;&gt;&lt;div class=&quot;g-plusone&quot; data-size=&quot;medium&quot; data-annotation=&quot;bubble&quot; data-href=&quot;https://web-engineering.info/node/49&quot;&gt;&lt;/div&gt;&lt;/div&gt;
          &lt;div class=&quot;easy_social-widget easy_social-widget-linkedin last&quot;&gt;&lt;script type=&quot;in/share&quot; data-url=&quot;https://web-engineering.info/node/49&quot; data-counter=&quot;right&quot;&gt;&lt;/script&gt;&lt;/div&gt;
  &lt;/div&gt; &lt;!-- /.easy_social_box --&gt;</description>
 <pubDate>Thu, 10 Dec 2015 02:44:23 +0000</pubDate>
 <dc:creator>gwagner</dc:creator>
 <guid isPermaLink="false">49 at https://web-engineering.info</guid>
 <comments>https://web-engineering.info/node/49#comments</comments>
</item>
</channel>
</rss>
