In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-20 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)05/31 Report--
This article introduces the knowledge of "methods used in JavaScript asynchronous programming". Many people will encounter this dilemma in the operation of actual cases, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!
According to Wikipedia, events that occur independently of the main control flow are called asynchronous. For example, there is a piece of code that executes sequentially
Void function main () {fA (); fB ();} ()
FA = > fB is executed sequentially, fA always executes before fB, and they are synchronous relationships. Use setTimeout to postpone fB when joining
Void function main () {setTimeout (fA, 1000); fB ();} ()
At this point, fA is asynchronous relative to fB. The main function simply declares that the fA will be executed in a second, but not immediately. At this point, the control flow of fA is independent of main.
JavaScript-- is a naturally asynchronous language.
Because of setTimeout, JavaScript supports asynchronous programming, at least from the moment it was standardized by ECMA. Unlike sleep in other languages, setTimeout is asynchronous-it does not stop the current program from continuing to execute.
However, the popularity of Ajax plays an important role in the real development of asynchronous programming. The A (Asynchronous) in Ajax really points to the concept of asynchrony-this is still the era of IE5 and IE6.
Callback function-- the pain of Asynchronous programming
How to notify the developer after the execution of the asynchronous task? The callback function is the simplest and easiest way to implement it. So from the moment asynchronous programming was born, it was tied to the callback function.
For example, setTimeout. This function starts a timer and executes the specified function after the specified time is exceeded. For example, the number 1 is output after one second, and the code is as follows:
SetTimeout (() = > {console.log (1);}, 1000)
Routine usage. If the requirements change, you need to output a number per second (not in setInterval, of course), and beginners in JavaScript may write code like this:
For (let I = 1; I
< 10; ++i) { setTimeout(() =>{/ / error! Console.log (I);}, 1000);}
The result of the execution is that after waiting for 1 second, all the results are output at once. Because the loop here starts 10 timers at the same time, each timer waits for 1 second. The result, of course, is that all timers time out at the same time after 1 second, triggering the callback function.
The solution is also simple, only need to start another timer after the previous timer expires, the code is as follows:
SetTimeout (()) = > {console.log (1); setTimeout () = > {console.log (2); setTimeout () = > {console.log (3); setTimeout () = > {console.log (4); setTimeout () = > {console.log (5); setTimeout () = > {/ /...}, 1000) }, 1000); 1000), 1000), 1000)}, 1000)
Layers of nesting, the result is such a funnel-shaped code. Some people may have thought of Promise in the new standard, which can be rewritten as follows:
Function timeout (delay) {return new Promise (resolve = > {setTimeout (resolve, delay);});} timeout (1000). Then () = > {console.log (1); return timeout (1000);}). Then () = > {console.log (2); return timeout (1000);}). Then () = > {console.log (3); return timeout (1000);}). Then () = > {console.log (4) Return timeout (1000);}). Then (() = > {console.log (5); return timeout (1000);}). Then () = > {/ /. });
The funnel code is gone, but the amount of code itself has not been reduced much. Promise didn't kill the callback function.
Because of the callback function, the loop cannot be used. Can not loop, then only consider recursion, the solution is as follows:
Let I = 1; function next () {console.log (I); if (+ + I)
< 10) { setTimeout(next, 1000); } } setTimeout(next, 1000); 注意虽然写法是递归,但由于 next 函数都是由浏览器调用的,所以实际上并没有递归函数的调用栈结构。 Generator——JavaScript 中的半协程 很多语言都引入了协程来简化异步编程,JavaScript 也有类似的概念,叫做 Generator。 MDN 上的解释:Generator 是一种可以中途退出之后重入的函数。他们的函数上下文在每次重入后会被保持。简而言之,Generator 与普通 Function ***的区别就是:Generator 自身保留上次调用的状态。 举个简单的例子: function *gen() { yield 1; yield 2; return 3; } void function main() { var iter = gen(); console.log(iter.next().value); console.log(iter.next().value); console.log(iter.next().value); }(); 代码的执行顺序是这样: 请求 gen,得到一个迭代器 iter。注意此时并未真正执行 gen 的函数体。 调用 iter.next(),执行 gen 的函数体。 遇到 yield 1,将 1 返回,iter.next() 的返回值即为 { done: false, value: 1 },输出 1 调用 iter.next()。从上次 yield 出去的地方继续往下执行 gen。 遇到 yield 2,将 2 返回,iter.next() 的返回值即为 { done: false, value: 2 },输出 2 调用 iter.next()。从上次 yield 出去的地方继续往下执行 gen。 遇到 return 3,将 3 返回,return 表示整个函数已经执行完毕。iter.next() 的返回值即为 { done: true, value: 3 },输出 3 调用 Generator 函数只会返回一个迭代器,当用户主动调用了 iter.next() 后,这个 Generator 函数才会真正执行。 你可以使用 for ... of 遍历一个 iterator,例如 for (var i of gen()) { console.log(i); } 输出 1 2,*** return 3 的结果不算在内。想用 Generator 的各项生成一个数组也很简单,Array.from(gen()) 或直接用 [...gen()] 即可,生成 [1, 2] 同样不包含***的 return 3。 Generator 是异步的吗 Generator 也叫半协程(semicoroutine),自然与异步关系匪浅。那么 Generator 是异步的吗? 既是也不是。前面提到,异步是相对的,例如上面的例子 function *gen() { yield 1; yield 2; return 3; } void function main() { var iter = gen(); console.log(iter.next().value); console.log(iter.next().value); console.log(iter.next().value); }(); 我们可以很直观的看到,gen 的方法体与 main 的方法体在交替执行,所以可以肯定的说,gen 相对于 main 是异步执行的。然而此段过程中,整个控制流都没有交回给浏览器,所以说 gen 和 main 相对于浏览器是同步执行的。 用 Generator 简化异步代码 回到最初的问题: for (let i = 0; i < 10; ++i) { setTimeout(() =>{console.log (I);}, 1000); / / wait for the above setTimeout execution to be completed}
The key is how to wait for the previous setTimeout to trigger the callback before executing the next loop. If we use Generator, we can consider yield out after setTimeout (the control flow is returned to the browser), and then next in the callback function triggered by setTimeout to return the control flow to the code and execute the next loop.
Let iter; function* run () {for (let I = 1; I)
< 10; ++i) { setTimeout(() =>Iter.next (), 1000); yield; / / wait for the above setTimeout execution to finish console.log (I);}} iter = run (); iter.next ()
The order of execution of the code is as follows:
Request run to get an iterator iter. Notice that the function body of run is not actually executed at this time.
Call iter.next () to execute the function body of run.
The loop begins and I is initialized to 1.
Execute setTimeout, start a timer, and delay the execution of the callback function by 1 second.
When you encounter yield (that is, yield undefined), the control flow returns to the iter.next () of * *. Because there is no other code behind, the browser gains control, responds to user events, executes other asynchronous code, and so on.
1 second later, setTimeout times out and executes the callback function () = > iter.next ().
Call iter.next (). Continue from where you left yield last time, which is console.log (I), and output the value of I.
At the end of one cycle, I increases from 2 to 2, go back to step 4 and continue
……
This implements requirements similar to synchronous sleep.
Async and await-- write asynchronous code with synchronous syntax
After all, the above code requires manual definition of iterator variables and manual next;. More importantly, it is tightly coupled with setTimeout and cannot be used in general.
We know that Promise is the future of asynchronous programming. Can you use Promise in combination with Generator? The result of this consideration is the async function.
The code obtained with async is as follows
Function timeout (delay) {return new Promise (resolve = > {setTimeout (resolve, delay);});} async function run () {for (let I = 1; I < 10; + + I) {await timeout (1000); console.log (I);}} run ()
According to Chrome's design documentation, the async function is internally compiled and executed as Generator. The run function itself returns a Promise to let the main tone function know when the run function has finished executing. So run () can be followed by .then (xxx), or even directly await run ().
Note that sometimes we do need several asynchronous events to execute in parallel (such as calling two interfaces and executing subsequent code after both interfaces return), so don't overuse await, for example:
Const a = await queryA (); / / wait for const b = await queryB () after queryA execution is completed; / / execute queryB doSomething (a, b)
At this point, queryA and queryB are executed serially. You can modify it slightly:
Const promiseA = queryA (); / / execute queryA const b = await queryB (); / / execute queryB and wait for its execution to finish. At the same time, queryA is also executing. Const a = await promiseA (); / / at this time the queryB execution has finished. Continue to wait for queryA execution to finish doSomething (a, b)
Personally, I prefer to write as follows:
Const [a, b] = await Promise.all ([queryA (), queryB ()]); doSomething (a, b)
Use await and Promise together, the effect is better!
This is the end of the content of "methods used in JavaScript Asynchronous programming". Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.