브라우저 기반 이벤트 폴링 메커니즘(및 Node.js의 이벤트 폴링 메커니즘), JavaScript는 종종 다음에서 실행됩니다. 비동기 환경. 자바스크립트 자체 언어의 특성(프로그래머가 스레드/프로세스를 제어할 필요가 없음)으로 인해 js에서 비동기 프로그래밍을 해결하는 것이 매우 중요합니다. 완전한 프로젝트에서 js 개발자가 비동기 작업에 직면하지 않는 것은 불가능하다고 말할 수 있습니다. 이 기사에서는 몇 가지 고전적인 JavaScript 비동기 프로그래밍 직렬화 방법을 자세히 소개하고 ES6에서 제공하는 Promise 순차 실행 방법도 간략하게 소개합니다.
URL 매개변수를 받는 ajax()
메서드가 있다고 가정합니다. 주소에 대한 비동기 요청을 수행하고 두 번째 매개변수인 요청 끝에 콜백 함수를 실행합니다.
ajax(url,function(result){ console.log(result); });
이 메서드는 거의 모든 프런트엔드 개발자가 사용하는 콜백 함수 메서드라고 할 수 있습니다. 이러한 콜백 메커니즘을 사용하면 개발자는 서버 요청이 언제 반환될지 추측하기 위해 다음과 같은 코드를 작성할 필요가 없습니다.
var result=ajax(url); setTimeout(function(result){ console.log(result); },400);
여기에서 표현하고 싶은 내용을 이해해야 합니다. 우리가 만드는 Ajax 요청이 400밀리초 이내에 완료된다고 가정하고 400밀리초 지연으로 타이머를 설정했습니다. 그렇지 않으면 undefined
중 result
을 작업하게 됩니다.
그러나 프로젝트가 확장됨에 따라 점차적으로 나타나는 문제가 있습니다. 시나리오에서 여러 계층의 중첩된 콜백 함수가 필요한 경우 코드를 읽고 유지 관리하기가 어려워집니다.
ajax(url0,function(result0){ ajax(result0.url1,function(result1){ ajax(result1.url2,function(result2){ console.log(result2); }); }); });
인라인 콜백 함수에서 노출되는 코드 혼동 문제를 해결하기 위해 유사한 문제를 해결하기 위한 외부 함수 호출을 도입합니다.
function handle2(result){ console.log(result); }function handle1(result){ ajax(result.url,function(result){ handle2(result); }); } ajax(url,function(result){ handle1(result); });
이런 방식으로 인라인 함수를 분할하면 다음과 같은 이점이 있습니다. 외부 함수 최적화 호출 방법을 사용하면 코드를 크게 간결하게 유지할 수 있습니다.
Nimble, Step, Seq 등 널리 사용되는 JavaScript 프로세스 제어 도구를 관찰하면서 간단한 디자인 패턴인 콜백 관리자를 통한 제어를 학습합니다. 비동기 JavaScript 실행 flow에서 다음은 일반적인 콜백 관리자의 주요 코드 예입니다.
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(); } ]);
우리는 Flow
컨트롤러를 초기화하고 series
및 next
라는 두 가지 함수 속성을 설계했습니다. 우리가 작성한 비즈니스 메소드 내에서는 메소드 마지막에 Flow.next()
을 호출하면 다음 메소드가 순차적으로 실행되고, series
메소드를 실행하면 비동기 함수가 순차적으로 실행됩니다. 코어 컨트롤러를 통해 비동기 함수 호출을 관리하는 이러한 방식은 프로그래밍 프로세스를 단순화하여 개발자가 비즈니스 로직에 더 많은 에너지를 쏟을 수 있도록 합니다.
아마도 위에서 소개한 비동기 방식은 실제 개발의 비즈니스 시나리오를 충족하지 못할 수도 있습니다. a()
, b()
, c()
세 가지 메서드 a와 b는 종속성이 없으며 비동기적으로 수행될 수 있습니다. 그러나 c는 a와 b가 모두 완료된 후에만 트리거될 수 있습니다. 이러한 논리적 구현을 충족하기 위해 코드의 실행 흐름을 제어하는 전역 카운터를 추가합니다.
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의 완료를 모니터링하기 위해 전역 변수 플래그를 설정합니다. 메서드 b는 200밀리초 타이머를 설정하여 네트워크 환경을 시뮬레이션하고 메서드 b가 실행된 후 결국 메서드 c를 성공적으로 호출합니다. 이러한 방식으로 a()
, b()
및 c()
메서드에 대한 종속 호출을 구현합니다.
위의 솔루션을 복잡한 시나리오에 적용하면 다음과 같은 문제가 발생합니다. 제품이 여러 버전 반복을 거쳤고 c 메서드는 더 많은 방법이 있으므로 카운터 플래그는 제품 반복 프로세스 중에 지속적으로 변경되어야 합니다. 위의 두 가지 상황이 발생하면 코드의 논리가 혼란스러워집니다. 플래그 태그가 간결하고 올바른지 여부는 제품 반복에 크게 영향을 받습니다. 따라서 우리는 데이터 중심의 최적화 개선을 제안합니다.
실제 개발 시나리오에서 메서드 종속성이 존재하는 이유는 기본적으로 데이터 종속성이 존재하기 때문입니다. 위의 간단한 예에서 메서드 c는 메서드 a와 메서드 b의 작업 결과에 따라 달라집니다. 플래그가 0인지 여부. 따라서 종속 메서드가 데이터 처리를 완료했는지 확인하여 마커가 0으로 설정되었는지 확인하는 것으로 대체할 수 있습니다. 이 예에서는 c 메서드에서 aValue와 bValue가 할당을 완료했는지 확인합니다.
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();
데이터 지향 검사 방법을 통해 향후 확장 시에는 checkDependency
개체에 대한 액세스만 추가하면 됩니다. 새로운 메소드 비동기 종속 메소드의 순차적 실행을 달성하기 위해 c 메소드에서 해당 속성의 존재를 수정하고 확인하십시오.
자바스크립트에서 비동기 메소드의 복잡성을 해결하기 위해 공식에서는 통합 제어 메소드를 도입했습니다:
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"); });
위의 예 코드는 기본 Promise 애플리케이션을 보여줍니다. 아마도 실제 시나리오에서는 다음 체인 호출이 더 일반적일 것입니다.
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中文网(www.php.cn)!