Based on the browser's event polling mechanism (and the event polling mechanism in Node.js), JavaScript often Runs in an asynchronous environment. Due to the characteristics of the JavaScript language itself (which does not require programmers to control threads/processes), it is very important to solve asynchronous programming in js. It can be said that in a complete project, it is impossible for js developers not to face asynchronous operations. This article will introduce in detail several classic JavaScript asynchronous programming serialization methods, and will also briefly introduce the Promise sequential execution method provided by ES6.
Suppose we have an ajax()
method, He receives a url parameter, initiates an asynchronous request to the address, and executes the second parameter - a callback function at the end of the request:
ajax(url,function(result){ console.log(result); });
It can be said that this method is used by almost every front-end developer. The callback function method, with such a callback mechanism, developers do not need to write code like the following to guess when the server request will return:
var result=ajax(url); setTimeout(function(result){ console.log(result); },400);
You should be able to understand what I want to express here. We set a timer with a delay of 400 milliseconds, assuming that the ajax request we make will be completed within 400 milliseconds. Otherwise, we will operate on a result
of undefined
.
But there is a problem that gradually emerges as the project expands: if the scene requires us to have multiple layers of nested callback functions, the code will become difficult to read and maintain:
ajax(url0,function(result0){ ajax(result0.url1,function(result1){ ajax(result1.url2,function(result2){ console.log(result2); }); }); });
In order to solve the code confusion problem exposed by inline callback functions, we introduce external function calls to solve similar problems:
function handle2(result){ console.log(result); }function handle1(result){ ajax(result.url,function(result){ handle2(result); }); } ajax(url,function(result){ handle1(result); });
By splitting inline functions in this way, we can call the optimization of external functions Method can greatly keep the code concise.
Observing popular JavaScript process control tools, such as Nimble, Step, and Seq, we will learn a simple design pattern: control through a callback manager Asynchronous JavaScript execution process, the following is a key code example of a typical callback manager:
var Flow={};//设置next方法,在上一个方法完成时调用下一个方法Flow.next=function(){ if(this.stack[0]){ //弹出方法栈中的第一个方法,并执行他 this.stack.shift()(); } };//设置series方法,接收一个函数数组,并按序执行Flow.series=function(arr){ this.stack=arr; this.next(); };//通过Flow.series我们能够控制传入的函数的执行顺序Flow.series([ function(){ //do something console.log(1); Flow.next(); }, function(next){ //do something console.log(2); Flow.next(); } ]);
We initialized a Flow
controller and designed a series
for him and next
two function attributes. Within the business method we wrote, the next method is triggered sequentially by calling Flow.next()
at the end of the method; the asynchronous function is sequentially executed by executing the series
method. This way of managing asynchronous function calls through the core controller simplifies our programming process, allowing developers to devote more energy to business logic.
Perhaps the asynchronous method introduced above still cannot meet the business scenarios in actual development: Suppose we have## There are three methods: #a(),
b(),
c(). A and b have no dependency and can be performed asynchronously. But c can only be triggered after both a and b are completed. In order to meet such a logical implementation, we add a global counter to control the execution flow of the code:
var flag=2;var aValue,bValue;function a(){ aValue=1; flag--; c(); }function b(){ setTimeout(function(){ bValue=2; flag--; c(); },200); }function c(){ if(flag==0){ console.log("after a and b:"+(aValue+bValue)); } } a(); b();
a(),
b(),
c().
In real development scenarios, the reason for the existence of method dependencies is basically because of the existence of data dependencies. For the simple example above: method c depends on the results of the operations of method a and method b, rather than whether the flag is 0. Therefore, we can replace checking whether the marker has been set to 0 by checking whether the dependent method has completed data processing. In this example, we check whether aValue and bValue have completed assignment in the c method:
function c(){ if(aValue!==undefined && bValue!==undefined){ console.log("after a and b:"+(aValue+bValue)); } }
var checkDependency={};var aValue,bValue;function a(){ aValue=1; checkDependency.a=true; c(); }function b(){ setTimeout(function(){ bValue=2; checkDependency.b=true; c(); },200); }function c(){ if(checkDependency.a && checkDependency.b){ console.log("after a and b:"+(aValue+bValue)); } } a(); b();
checkDependencyModify the object and check the existence of the corresponding attributes in the c method to achieve the sequential execution of asynchronous dependent methods.
var bool=false;/* * 新建一个Promise实例,向构造函数传入一个异步执行函数 * 异步函数会接受两个参数,由Promise传入,对应then方法中传入的方法 */var promise=new Promise(function(resolve,reject){ setTimeout(function(){ if(bool){ //根据执行情况相应调用resolve和reject resolve(bool); }else{ reject(bool); } },200); });//通过then向Promise实例传入解决方法promise.then(function resolve(result){ console.log("success"); },function reject(result){ console.log("failure"); });
new Promise(function(res,rej){ if(/*异步调用成功*/){ res(data); }else{ rej(error); } }).then(function resolve(result){ console.log("success"); },function reject(result){ console.log("failure"); });
如果对Promise感兴趣的话,可以在网上寻找资料继续深入学习!
关于Promise的兼容性,通常web前端JavaScript代码中不会直接使用Promise(通过caniuse.com网站查询发现Android4.4不支持Promise)。如果特别想使用的,往往会在项目中附带一些补足兼容性的promise类库;而后端Node.js可以放心使用Promise类来管理异步逻辑。
以上就是详解JavaScript异步编程技术的内容,更多相关内容请关注PHP中文网(m.sbmmt.com)!