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);
打印结果如下:
我们传入的都是非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); });
打印结果如下:
all方法是将三个promise的结果都接收的,而race方法之接收了第一个promise对象的结果。在promisereject的时候,all方法调用的是catch回调。
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); });
打印结果如下:
但是使用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每种库的实现机制可能不尽相同,但大致的基本原理是相同的。