The execution environment of JavaScript is single-threaded.

Source: Internet
Author: User

As we all know, the execution environment of JavaScript is single-threaded. The so-called single-threaded task can only complete one task at a time, and the scheduling method of the task is queuing, which is the same as waiting at the gate of the railway station restroom, if the person in front is not done, you can only wait in the queue. Add a latency in the event queue, so that the problem can be mitigated. A: Hey, buddy, hurry up! B: It takes me three minutes. You have to wait ~ A: Okay. Remember to call me ~ You (C) are waiting. Call you when you're done ~ C: Well !... Tell the people in the queue an accurate time, so that the people in the backend can use this time to do other things, rather than all people complain after the queue. I wrote a program to solve this problem:/*** @ author Barret Lee * @ email barret.china@gmail.com * @ description event queue management, latency */var Q = {// save queue information a: [], // Add to queue q: function (d) {// Add to the queue. if it is not a function or number, if (! /Function | number /. test (typeof d) return; Q. a. push (d); // return the reference to itself return Q;}, // execution queue dequeue d: function () {var s = Q. a. shift (); // if the end of the queue is reached, if (! S) return; // if it is a function, execute it directly, and then continue dequeue if (typeof s = "function") {s (), Q. d (); return;} // if it is a number, this number is used as the delay time. Delay dequeue setTimeout (function () {Q. d () ;}, s) ;}; this section adds a lot of comments. I believe that all the children's shoes with the JS foundation can be understood and tested using the above Code: // process record function record (s) {var div = document. createElement ("div"); div. innerHTML = s; console. log (s); document. body. appendChild (div);} Q. q (function () {record ("0 <I style = 'color: Blue'> 3 s later, 0 sets 1 Call in </I> ");}). q (3000) // delay 3 s. q (function () {record ("1 <I style = 'color: Blue'> after 2 s, 1 calls 2 in </I> ");}). q (2000) // 2 S latency. q (function () {record ("2 <span style = 'color: red'> no one is behind. OK, the restroom is closed ~ </Span> ") ;}). d (); // The execution queue can stamp this DEMO. You can also directly run this program: // event queue management, including the delayed Running code. I. Javascript asynchronous programming principle obviously, the above method is similar to the bank account acquisition wait, but we don't know how long it will take for the last person to complete the bank account acquisition. This is a non-blocking method to handle the problem. Next we will discuss the asynchronous programming principles in JavaScript. 1. setTimeout Function disadvantages of latency processing is indispensable to setTimeout. Many people understand the setTimeout function as follows: if the latency is n, the function will be executed after n milliseconds. In fact, this is not the case. There are three problems. One is the timeliness of the setTimeout function. You can test the following code: var d = new Date, count = 0, f, timer; timer = setInterval (f = function () {if (new Date-d> 1000) clearInterval (timer), console. log (count); count ++;}, 0); it can be seen that the number of running operations in 1 s is about 200, some people may say that it is because the conversion of new Date and function scope consumes time. Otherwise, you can try this code again: var d = new Date, count = 0; while (true) {if (new Date-d> 1000) {console. log (count); break;} count ++;} Here I show 35 1813, that is to say, the count has accumulated more than 35 million times. What does this mean? The shortest cycle of setInterval and setTimeout functions is about 5 ms. This value is also mentioned in the HTML specification: 5. let timeout be the second method argument, or zero if the argument was omitted. if the timeout parameter is not written, the default value is 07. if nesting level is greater than 5, and timeout is less than 4, then increase timeout to 4. if the nested hierarchy is greater than 5 and the value set for timeout is smaller than 4, take 4 directly. to make functions more responsive, Some browsers provide more advanced interfaces (when the timeout is 0, you can use the following method to replace it with a higher speed): requestAnimationFrame which allows Java When a Script processes an animation at a speed of 60 + frames/s, its running interval is much shorter than setTimeout. @ Situ zhengmei: he is suitable for animation. He can slow down the movement when the tab loses focus or minimizes, thus saving CPU resources. His running interval is indeed longer than setTimeout. Process. nextTick is a function in NodeJS. It can be used to almost achieve the efficiency of the while LOOP shown above. ajax or the readState change of the inserted node MutationObserver is about 2-3 mssetimmediate postMessage, which is quite fast... these things will be discussed in detail next time. I saw the relevant content when studying the source code of situ zhengmei aveon. If you are interested, you can see: // use the fastest asynchronous callback var BrowserMutationObserver = window Based on the browser situation. mutationObserver | window. webKitMutationObserverif (BrowserMutationObserver) {// chrome18 +, safari6 +, firefox14 +, ie11 +, opera15 aveon. nextTick = function (callback) {// 2-3 ms var input = DOC. createElement ("input") var observer = new BrowserMutationObserver (function (mutations) {mutations. forEach (function () {Callback ()}) observer. observe (input, {attributes: true}) input. setAttribute ("value", Math. random ()} else if (window. VBArray) {// in IE, this usually takes 1 ms and has no side effects. No request is found. // setImmediate, if it is executed only once, needs to be up to ms as it is set to setTimeout. nextTick = function (callback) {var node = DOC. createElement ("script") node. onreadystatechange = function () {callback () // triggers node in the interactive stage. onreadystatechange = null root. r EmoveChild (node) node = null} root. appendChild (node)} else {aveon. nextTick = function (callback) {setTimeout (callback, 0)} I have mentioned a bunch of them. The purpose is to explain that setTimeout has a certain interval, the execution is not set to n milliseconds, but to n milliseconds. There may be a little delay (about 2 ms ). Then let's talk about his second disadvantage. first look at the code: var d = new Date; setTimeout (function () {console. log ("show me after 1 s, but you konw:" + (new Date-d) ;}, 1000); while (1) if (new Date-d> 2000) break; we expect the console to output results after 1 s, but in fact it runs after 2075 ms, this is the headache caused by a single JavaScript thread. The while LOOP blocks the execution of the setTimeout function. Next is his third problem. try .. catch cannot catch his Error: try {setTimeout (function () {throw new Error ("I don't want this Error to happen! ") }, 1000);} catch (e) {console. log (e. message);} it can be said that setTimeout is an indispensable role in asynchronous programming, but it has so many problems, which requires us to avoid it in a more appropriate way! 2. asynchronous asynchronous functions and non-blocking functions are closely related. When we request data through ajax, we generally adopt the Asynchronous Method: var xhr = new XMLHttpRequest (); xhr. open ('get', '/', true); xhr. send (); xhr. onreadystatechange = function () {console. log (xhr. status);} In xhr. in open, we set the third parameter to true, that is, asynchronous loading. When the state changes, xhr immediately responds and triggers related functions. Someone has thought about using this method: while (1) {if (xhr. status = "complete") {// dosomething (); break;}. In fact, the judgment here is already in an endless loop, even if the status of xhr has changed, this endless loop cannot be jumped out, so the asynchronous here is based on events. A function will cause another function to run in the future. The latter is taken from the event queue (if this function is passed as a parameter to the former, it is called a callback function, callback ). -- Taken from Async Javascript because of the single-threaded nature of JavaScript, it does not provide a mechanism to prevent the function from returning before its asynchronous operation ends. In fact, unless the function returns, otherwise, no asynchronous events are triggered. 3. common asynchronous model 1) the most common method is that higher-order functions (generic functions) step1 (function (res1) {step2 (function (res2) {step3 (function (res3) {//...});});}); the degree of decoupling is very low. If too many parameters are input, it will become messy! This is the most common way to send a function as a parameter and then call back. 2) event listening f. on ("evt", g); function f () {setTimeout (function () {f. trigger ("evt") ;}} the native methods provided by JS and the browser are basically based on the event trigger mechanism, and the coupling degree is very low, but the event cannot be controlled by the process. 3) Publish/subscribe (Pub/Sub) E. subscribe ("evt", g); function f () {setTimeout (function () {// f task code E. publish ("evt") ;}, 1000) ;}submit all events to the E controller for management. You can fully master the number of times subscribed to events and the subscriber information, easy to manage. 4) The Promise object (deferred object). For more information, see qu's article. The Promise/A + specification is A supplement and modification to the Promise/A specification. It is designed to unify interfaces in asynchronous programming. asynchronous programming in JS is very common, there are also many asynchronous libraries. If the interface is not unified, it is also very painful for developers. In the Promises/A specification, each task has three states: default (pending), complete (fulfilled), and rejected ). The default status can be transferred to the completion status in one way. This process is called resolve, and the corresponding method is deferred. resolve (promiseOrValue); the default status can also be transferred to the failed status in one way. This process is called reject and the corresponding method is deferred. reject (reason); by default, you can also use deferred. Y (update) is used to declare the task execution information, such as the execution progress. Status transfer is one-time. Once the task is changed from initial pending to another status, the next task is executed. Ii. error handling in asynchronous functions some problems with the setTimeout function have been mentioned earlier, try in JS .. the catch mechanism cannot get the error in the setTimeout function. What is the impact scope of a throw error? I did a test: <script type = "text/javascript"> throw new Error ("error"); console. log ("show me"); // It is not printed </script> <script type = "text/javascript"> console. log ("show me"); // printed </script> from the test above, we can see that the range of throw new Error is to block the program running in a script label, however, the following script is not affected. This test has no effect. I just want to tell you not to worry that an Error will affect global function execution. Therefore, the code can be divided into two sections, one section that may cause errors and one section that ensures that no errors occur, so that the global code will not die. Of course, such a processing method is not feasible. Fortunately, there is a convenient function on the window global object, window. error, we can use it to capture all the errors and handle them accordingly, such as window. onerror = function (msg, url, line) {console. log (msg, url, line); // true must be returned; otherwise, Error will still trigger the blocking program return true;} setTimeout (function () {throw new Error ("error"); // console: // Uncaught Error: error path/to/ie6bug.html 99}, 50); we can encapsulate the Error: window. onerror = function (msg, url, line) {// truncates "Uncaught Error: error" to obtain the Error Type var Type = msg. slice (16); switch (type) {case "TooLarge": console. log ("The number is too large"); case "TooSmall": console. log ("The number is too Small"); case "toouugly": console. log ("That's Barret Lee ~ "); // If it is not our predefined error type, it is reported to the background monitoring default: $ & $. post & $. post ({"msg": msg, "url": url, "line": line})} // remember to return true here; otherwise, the program is blocked by an error. Return true;} setTimeout (function () {if (something) throw new Error ("TooUgly"); // console: // That's Barret Lee ~ }, 50); obviously, the error is no longer terrible. You can use the onerror function provided by window to easily handle the error and make a timely response. If an unknown error occurs, you can post the information to the background, which is also a very good monitoring method. However, there is a problem in this process. We have blocked all the errors, but some errors should have blocked the running of all programs. For example, if an error occurs when we obtain data through ajax and the program mistakenly assumes that the data has been obtained, we should have stopped the work and reported this fatal error, but this error is reported by window. onerror is intercepted and the error is handled. Window. onerror is a particularly violent fault tolerance method. try .. the same applies to catch. Their underlying implementation is implemented using the goto statement in C/C ++. Once an error is found, no matter how deep the current stack is, no matter where the code runs, directly go to the top layer or try .. at the layer captured by catch, this kind of one-kick-and-open error processing method is not very good, I think. Iii. Introduction to JavaScript multithreading technology the concept of asynchronous programming and non-blocking is closely related, while the Worker object in JavaScript can create an independent thread to process data, which naturally handles the blocking problem. We can hand over the heavy computing tasks to the Worker and Post the data after the processing. Var worker = new Worker (". /outer. js "); worker. addEventListener ("message", function (e) {console. log (e. message) ;}); worker. postMessage ("data one"); worker. postMessage ("data two"); // outer. jsself. addEventListener ("message", function (e) {self. postMessage (e. message) ;}); the preceding is a simple example. If we create multiple workers, we must determine the e.tar get value when listening to The onmessage event to learn the data source. Of course, we can also encapsulate the data source in e. message. Worker is a useful tool. I can use setTimeout, setInterval, and other functions in Worker, or obtain information about navigator, the most important thing is that he can create ajax objects and WebSocket objects, that is, he can directly request data from the server. However, he cannot access the DOM information, and cannot directly process the DOM. In fact, the main thread and Worker are two independent threads. If both of them can modify the DOM, isn't it necessary to set a troublesome mutex variable ?! It is worth noting that in Worker, we can use the importScript function to directly load the Script, but this function is synchronized, that is, it will freeze the Worker thread until the Script is loaded. ImportScript ("a. js", "B. js", "c. js"); you can add multiple parameters. The order of loading is the order of parameters. What do I usually do with Worker? The calculation and encryption of data is particularly time-consuming, for example, the calculation of the Fibonacci function value. For example, the MD5 Value Comparison of a file, the calculation of the MD5 value of a large file is also time-consuming. The coding and decoding of audio and video streams should not be done by the technical staff involved in such work. If you are interested, you can take a look at this technology. It is a WebRTC shared by hehe123 in Hangzhou. The content is not bad. Wait, you think that all time-consuming things can be handed over to him and then talk about SharedWorker. This is a trend in the future of the web communication field. Some people think that WebSocket is already very good, however, in some WebSocket-based architectures, servers need to maintain a WebSocket code for each page, while SharedWorker is very powerful. It is common for multiple pages. <Input id = "Indium"/> <input type = "button" id = "btn" value = "send"/> <script type = "text/javascript"> var sw = new SharedWorder (". /outer. js "); // bind the event sw. port. onmessage = function (e) {console. log (e. data) ;}; btn. onclick = function () {sw. port. postMessage (Indium. value); indium. value = "" ;}; // create a connection and start listening to sw. port. start (); </script> // outer. jsvar pool = []; onconnect = function (e) {// place the connection page in the connection pool. push (e. ports [0 ]); // Broadcast immediately after receiving the message e. ports [0]. onmessage = function (e) {for (var I = 0; I <pool. length; I ++) // broadcast information pool [I]. postMessage (e. data) ;}}; a simple understanding of SharedWorker is to use a running thread as a web Background Program without the involvement of background scripts. This web communication, especially for game developers, I think it is a good news!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.