ES6的Promise学习讲解以及jQuery的Promise对象
2017-04-04 18:28

ES6的Promise

ES6中提供了原生的Promise对象。用法和原理跟我前面写的Promise插件实质是一样的,都是通过一层包装来让异步调用看起来更像同步调用,同时解决异步调用多层嵌套导致代码维护困难的问题。

ES6的Promise使用也很简单:

var prom=new Promise(function(resolve,reject){
    $.post("images/timg.jpg",function(){
        console.log("ajax");
        resolve();
        console.log("had resolve");
    });
});
prom.then(function(){
    console.log("call in then");
});

我们通过new操作符创建了一个Promise对象,可以通过then方法来定义它后续的执行代码。在promise内部的ajax调用,要调用resolve()方法来通知执行then中的回调函数。如果你不调用resolve方法,then中的回调是不会调用的。

Promise对象有几个静态方法,

Promise.resolve(),Promise.reject();

var prom=Promise.resolve(123);
console.log(prom);
var prom2=Promise.reject(235);
console.log(prom2);

打印结果如下:

blob.png

我们传入的都是非Promise对象,这两个方法对他们进行了Promise对象的包装。而且他们作为了promisevalue值会传递给后面的then,catch方法。

在promise实例中,then方法用来处理异步调用成功的回调,catch方法用来处理调用失败的回调。

Promise.all(),Promise.race()这两个静态方法,用来处理多个异步请求,他们接受promise对象的数组对象。非promise的对象会包装成promise对象。

all方法在所有请求完成后才会调用then方法,或者有一个失败调用catch。

race方法在有一个异步成功返回后就会调用then方法,或者有一个失败调用catch。

var prom=Promise.resolve(235);
var prom2=Promise.resolve(356);
Promise.all([prom,prom2,635]).then(function(values){
    console.log(values);
});
var prom3=new Promise(function(res,rej){
    setTimeout(function(){
        res(636);
        console.log("第三个Promise");
    },2000);
});
Promise.race([prom,prom2,prom3]).then(function(value){
    console.log(value);
});
var prom4=Promise.reject(999);
Promise.all([prom,prom2,prom4]).then(function(values){
    console.log(values);
}).catch(function(e){
    console.log("e:"+e);
});

打印结果如下:

blob.png

all方法是将三个promise的结果都接收的,而race方法之接收了第一个promise对象的结果。在promisereject的时候,all方法调用的是catch回调。

jQuery 的deferred对象

jquery的deffered对象跟promise的作用一样,但是它由于基于jquery库,所以使用上更方便。

 $.when($.post("images/big.jpg"), $.post("images/egg.jpg")).done(function(a1,a2){
         //console.log("图片资源加载完成");
 });

使用jquery的$.when方法实现的promise,可以方便的通过$.post,$.ajax等加载数据文件等。并且它的done方法中不用调用resolve,reject等函数。在jquery的ajax内部自己调用了resolve,reject等方法,因为我们可以更简便的处理异步调用。就像angular中的“$http.post('...').success(function(){})”一样,angular也是自己在$http服务内部调用了$q的resolve等方法来通知异步调用完成的。

$.get("test.php")
  .done(function(){ alert("$.get succeeded"); })//延迟成功
  .fail(function(){ alert("$.get failed!"); });//延迟失败

单个ajax可以也可以使用done,fail方法来作为成功或失败的回调函数。

$.get("test.php").then(
    function(){ alert("$.get succeeded"); },
    function(){ alert("$.get failed!"); }
);

jquery中也可以使用then方法,传递的两个回调,第一个是成功回调,第二个是失败回调。ES6的promise中的then方法跟它一样,但是ES6中提供了catch方法来处理失败,所以用catch方法显得更加语义化。

$.get("test.php").always( function() { 
  alert("$.get completed with success or error callback arguments"); 
} );

always方法表示无论成功或者失败都会被调用。

同样,jquery的deferred对象也可以脱离ajax自行定义调用

var der= $.Deferred();
der.done(function(msg){
    console.log(msg);
}).fail(function(msg){
    console.log(msg);
});
der.resolve("mooshine");

或者这样调用

var der= $.Deferred();
$.post("images/resizeApi.png",function(){
    der.resolve("mooshine");
});
der.done(function(msg){
    console.log(msg);
}).fail(function(msg){
    console.log(msg);
});

jquery还提供了resolveWith,rejectWith方法来传递this对象。

var der= $.Deferred();
var obj={name:"wang",sex:"girl"};
$.post("images/resizeApi.png",function(){
    der.resolveWith(obj,["mooshine"]);
});
der.done(function(msg){
    console.log(this);
    console.log(msg);
}).fail(function(msg){
    console.log(msg);
});

打印结果如下:

blob.png

但是使用resolveWidth方法,参数的传递要使用数组的形式,在1.9版本不使用数组会报错,这应该是一个bug。

此外,我们还可以在jquery包装的数组上使用promise对象。

$("div").animate({left:"200px"},3000,function(){});
$("div").promise().done(function(){
    console.log("div");
});

上面的console会在动画结束后打印,但是前提是我们使用jquery的动画。$("div").promise()是生成一个promise对象。

如果我们使用jquery库,那么jquery的Promise是比较有用的,不使用jquery库的时候ES6也给我们提供了一个Promise的原生对象。使用Promise的唯一目的就是增强代码的可读性。而我们学习Promise除了使用外,就是他的实现机制,Promise每种库的实现机制可能不尽相同,但大致的基本原理是相同的。

原创文章,转载请注明来自:妹纸前端-www.webfront-js.com.
阅读(2210)
辛苦了,打赏喝个咖啡
微信
支付宝
妹纸前端
妹纸前端工作室 | 文章不断更新中
京ICP备16005385号-1