>  기사  >  웹 프론트엔드  >  비동기 callbacks_jquery에서 jQuery의 promise와 지연된 개체의 역할

비동기 callbacks_jquery에서 jQuery의 promise와 지연된 개체의 역할

WBOY
WBOY원래의
2016-05-16 15:02:261238검색

1. 서문

콜백의 지옥에서 프런트 엔드를 천국으로 되돌리기 위해 jQuery는 Promise 개념도 도입했습니다. Promise는 코드의 비동기 동작을 더욱 우아하게 만드는 추상화입니다. Promise를 사용하면 동기 코드를 작성하는 것처럼 비동기 코드를 작성할 수 있습니다. jQuery는 버전 1.5부터 CommonJS Promise/A 사양의 헤비급 솔루션을 구현했지만 사양에 따라 엄격하게 구현되지 않았으며 일부 API 차이가 있습니다.

자, 기능을 살펴보겠습니다(이 글의 예는 jquery 버전 1.8 이상을 기반으로 합니다).

2. 예시

과거에는 애니메이션을 작성할 때 보통 다음과 같이 했습니다.

$('.animateEle').animate({
 opacity:'.5'
}, 4000,function(){
 $('.animateEle2').animate({
  width:'100px'
 },2000,function(){
  // 这样太伤了
  $('.animateEle3').animate({
   height:'0'
  },2000);
 });
});

콜백을 이렇게 사용하면 너무 해로울 것입니다. 다행히도 이 문제를 우아하게 해결하는 몇 가지 기본 제공되는 Promise 솔루션이 있습니다.

jQuery에서 제공하는 솔루션을 살펴보겠습니다.

var animate1 = function() {
 return $('.animateEle1').animate({opacity:'.5'},4000).promise();
};
var animate2 = function() {
 return $('.animateEle2').animate({width:'100px'},2000).promise();
};
var animate3 = function(){
 return $('.animateEle3').animate({height:'0'},2000).promise();
};
// so easy,有木有,so clear,有木有
$.when(animate1()).then(animate2).then(animate3);

분명히 변경된 코드가 이해하고 읽기 더 쉽습니다.

그러나 위 코드에서는 일부 세부 사항이 공개되지 않습니다. 조심하지 않으면 실수하기 쉽고 원하는 순서대로 애니메이션이 완성되는 효과를 얻을 수 없습니다. jQuery에서 제공하는 Promise 객체와 Deferred 객체의 메소드를 완벽히 이해하고 어떻게 사용하는지 살펴보자.

3. Promise 및 지연 객체 메서드

Promise 개체는 실제로 지연된 개체의 특별한 경우입니다. 왜냐하면 Promise 개체는 비동기 상태를 변경할 수 없지만 지연된 개체는 변경할 수 있기 때문입니다. 이는 분석법 설계에 명확하게 반영됩니다.

1.promise 객체 방식

일반적으로 DOM, 애니메이션, Ajax 관련 메소드에는 promise 메소드를 사용할 수 있습니다. promise 메소드를 호출하면 promise 객체가 반환됩니다. Promise 메소드는 체인에서 호출될 수 있습니다.

Promise 개체에는 세 가지 일반적인 메서드(완료, 실패, then)가 있습니다.

jquery에는 인터페이스 메소드가 너무 많아서 초기 이벤트 메소드 바인딩과 마찬가지로 결국에는 모두 분류되지 않습니다. 온이 그걸 처리하러 왔나요?

다음과 같은 코드 예시:

(1) DOM은 약속 방식을 사용합니다:

var box=$('#box');
box.promise().done(function(ele){
  console.log(ele);//jQuery box
});

(2) Ajax는 promise 메소드를 사용합니다(기본적으로 promise 객체를 반환하므로 promise 메소드를 명시적으로 호출할 필요가 없습니다).

$.post('/',{}).done(function(data){
  console.log('请求成功');
}).fail(function(){
  console.log('请求错误');
});

애니메이션 예시는 이미 존재하므로 다시 나열하지 않겠습니다.

2.지연 객체 방식

그럼 Deferred와 Promise의 차이점은 무엇인가요? 앞서 본 것처럼 Promise는 비동기 함수가 반환하는 객체입니다. 이러한 함수를 직접 작성하려면 deferred를 사용해야 합니다.

지연된 객체는 promise 객체와 동일한 작업을 수행할 수 있지만 done() 및 failure() 함수를 트리거하는 두 가지 함수가 있습니다.

연기된 객체에는 성공적인 결과를 처리하고 done()과 관련된 함수를 실행하는 해결() 함수가 있습니다. 거절() 함수는 실패한 결과를 처리하고 실패()와 관련된 함수를 실행하는 데 사용됩니다.

Resolve() 및 Reject() 함수 모두에 매개변수를 제공할 수 있으며, 그러면 둘 다 done() 및 실패()와 관련된 콜백 함수에 전달됩니다.

Promise 객체에는 Resolve() 및 Reject() 함수가 없습니다. 이는 Promise를 다른 스크립트에 넣었고 Promise가 Promise를 해결하거나 거부하는 것을 원하지 않기 때문입니다.

다음은 deferred의 간단한 예시입니다. html은 id 속성이 "result"인 단순한 빈 div입니다.

$('#result').html('waiting...');

var promise = wait();
promise.done(result);

function result() {
 $('#result').html('done');
}

function wait() {
 var deferred = $.Deferred();

 setTimeout(function() {
  deferred.resolve();
 }, 2000);

 return deferred.promise();
}  

그 중 wait() 함수는 Promise를 반환합니다. 2초 후에 구문 분석됩니다. setTimeout 외에도 애니메이션, 웹 작업자 등 비동기 함수의 모든 항목을 이러한 방식으로 사용할 수 있습니다. wait() 함수의 코드는 명확해야 합니다. 지연된 객체를 사용하지만 제한된 Promise 객체를 반환합니다.

지연된 객체, 즉 $.Deferred() 메소드와 $.when() 메소드를 사용하여 생성된 객체의 경우 일반적으로 사용되는 메소드는 다음과 같습니다.

resolve , reject , notify ;
done , fail , progress ;

약속, 그때, 항상 방법도 있습니다.

이렇게 형식을 지정하는 이유는 해당 메서드가 대응하기 때문입니다. 즉, 해결 메서드는 완료 콜백 실행을 트리거하고, 거부는 실패 콜백을 트리거하며, 알림은 진행 콜백을 트리거합니다.

코드 직접 보기:

var wait = function(ms) {
 var dtd = $.Deferred();
 setTimeout(dtd.resolve, ms);
 // setTimeout(dtd.reject, ms);
 // setTimeout(dtd.notify, ms);
 return dtd.promise(); //此处也可以直接返回dtd
};

wait(2500).done(function() {
 console.log('haha,师太,你可让老衲久等了');
}).fail(function() {
 console.log('失败了');
}).progress(function(res) {
 console.log('等待中...');
});

我们看到了,上面的代码中,在 wait 函数中,返回的是个 promise 对象,而不是 deferred 对象。

要知道, promise 对象是没有 resolve , reject , notify 等方法的,也就意味着,你无法针对 promise 对象进行状态更改,只能在 done 或 fail 中进行回调配置。所以,你如果这么调用 wait(2500).resolve() 将会报错,因为 wait(2500) 返回的是个 promise 对象,不存在 resolve 方法。

但是,这么做,有个好处,我们把 dtd 这个 deferred 对象放在了 wai t函数中,作为了局部变量,避免了全局的污染;进一步通过 promise 方法,转化 dtd 这个 deferred 对象为 promise 对象,避免了函数 wait 外部可能发生的状态更改(假如我们确实有这个需求)。

比如:

var wait = function(ms) {
 var dtd = $.Deferred();
 setTimeout(dtd.resolve, ms);
 // setTimeout(dtd.reject, ms);
 // setTimeout(dtd.notify, ms);
 return dtd; //此处也可以直接返回dtd
};

wait(2500).reject().fail(function(){
 console.log('失败了...............');
});

我们在外部更改了 wait 返回的 deferred 对象的状态,这样必然触发该对象的 fail 回调函数。

对于 always 方法,从字面意思上就很容易理解, deferred 对象无论是 resolve 还是 reject ,都会触发该方法的回调。

3.其它共性

此处讲讲 then 和 $.when 方法的使用。它们对 promise 对象也适用。

$.when 方法接受多个 deferred 对象或者纯javascript对象,返回 promise 对象。
then 方法依次接受三个回调,分别为 deferred 对象 resolve , reject , notify 后触发的回调,返回一个 promise 对象。注意,必须传入函数,而该函数只有返回一个 promise 对象,才能够让异步事件按照预期顺序来执行。
我们来看看最开始的动画示例代码, $.when(animate1()).then(animate2).then(animate3) , $.when 方法中接受了一个 animate1 的函数执行结果,也就是得到了一个 promise 对象,而后的 then 中,则只是接受了一个变量名,这样得到的结果是一个匿名的函数体,而该函数中返回的是 promise 对象。正好符合了我们对 then 接受参数的要求。

假如我们把执行语句改成: $.when(animate1()).then(animate2()).then(animate3()) ,这样造成的结果就是三个动画同步执行了。与 $.when(animate1(),animate2(),animate3()) 无异。

既然 then 是如此要求,那么与 then 方法类似的 done , fail , progress 也是一样的。

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.