在JavaScript中代码都是单线程执行的,所以JavaScript中全部的网络操做、浏览器事件都必须异步执行。在Promise
以前JavaScript处理异步的方式都是回调函数。能够说callback
的方式已经是深刻人心,那Promise
又是解决什么问题的呢?看下面一段代码:ajax
$.get('/getList',function(){ $.get('/getCount',function(){ $.get('/getDetail',function(){ //.... }) }) })
这段代码就是传统的callback
方式处理异步,能够看到刚刚3级嵌套代码层级就已经比较乱了,若是再加上一些逻辑代码那简直是没法直视。这就是咱们常说的==回调地狱==问题。代码可读性低,难以维护,没法复用。数组
Promise
的基本用法promise
var promise = new Promise((resolve,reject)=>{ setTimeout(function(){ //这里异步操做已经执行完了,就能够经过resolve告诉外界能够进行其余操做了 resolve('ok'); //reject('no'); },2000); }) promise.then(res=>{ console.log(res); // ok },err=>{ console.log(err); // no })
经过Promise
处理异步,先执行异步操做,不关心如何处理结果,经过Promise
对象的返回成功仍是失败,在未来的某个时刻执行结果处理函数。代码变得扁平化,且易读易维护。浏览器
resolve && reject
上面代码咱们经过 resolve 方法把 Promise 的状态置为完成态(Resolved),这时 then 方法就能捕捉到变化,并执行“成功”状况的回调。
而 reject 方法就是把 Promise 的状态置为已失败(Rejected),这时 then 方法执行“失败”状况的回调(then 方法的第二参数)。网络
一样三级回调的代码咱们再使用Promise
重构一遍异步
new Promise((resolve,reject)=>{ $.get('/getList',res=>{ resolve(res); }); }).then(res=>{ return new Promise((resolve,reject)=>{ $.get('/getCount',res=>{ resolve(res); }); }); }).then(res=>{ return new Promise((resolve,reject)=>{ $.get('/getDetail',res=>{ resolve(res); }) }); }).then(res=>{ //... });
能够看到不管有多少层回调,都不用互相嵌套,只须要等待Promise
对象“通知“执行便可。函数
当须要进行多步没有关联逻辑的异步操做时,可使用Promise.all
线程
Promise.all([ $.get('/getList'), $.get('/getCount'), $.get('/getDetail') ]).then(([data1,data2,data3])=>{ //then回调的参数是一个数组,顺组数序就是异步操做书写顺序 console.log(data1,data2,data3); },err=>{ console.log(err); });
all
方法中的参数应该是Promise
对象,由于ajax
函数返回的对象就是promise对象因此这里是能够执行的;data1,data2,data3
是按照异步操做书写顺序返回);race
的用法与all
类似,不一样点就是all
会等全部异步操做所有执行完后再执行then回调,而race
中只要有一个异步操做执行完成就马上执行then回调。code
Promise.race([ new Promise(function(resolve, reject){ setTimeout(function(){ console.log('函数一执行!'); resolve('11'); }, 1000); }), new Promise(function(resolve, reject){ setTimeout(function(){ console.log('函数二执行!'); resolve('22'); }, 1200); }) ]).then(result=>{ console.log('then执行'); console.log(result); },err=>{ console.log(err); }); //执行结果为: //函数一执行! //then执行 //11 //函数二执行!
能够看到函数一执行明显要比函数二快,因此执行了函数一后当即执行了then回调,==注意这时函数二依然会执行==,可是执行后不会再触发then回调的执行。对象
then
。new Promise((resolve,reject)=>{ //... }).then(resSuccess=>{ //成功 },resError=>{ //失败 });
catch
捕获new Promise((resolve,reject)=>{ //... }).then(resSuccess=>{ //成功 }).catch(resError=>{ //失败 });
==注==:catch
方式更经常使用,由于不单单能捕获到reject传递的参数,还能够捕获到成功的回调中发生的错误。
jQuery 用 $.Deferred 实现了 Promise 规范。
function fn1() { var def = $.Deferred(); //执行异步操做 setTimeout(function () { console.log('函数1!'); def.resolve('函数1执行完毕回调'); //def.reject('函数1执行完毕回调'); }, 1000); return def.promise(); } //then方法第一个参数接收成功回调,第二个参数是接收失败回调 fn1().then(res => { console.log(res); },err=>{ console.log(err); });
$.Deferred()
方法返回一个对象,咱们能够称之为Deferred
对象,该对象包含一些方法如:then、done、fail 等。jQuery
就是用这个Deferred
对象来实现Promise
规范的。
对于多级回调的状况也可使用then()
方法进行链式调用:
function fn1() { var def = $.Deferred(); //执行异步操做 setTimeout(function () { console.log('执行函数1!'); def.resolve('函数1执行完毕回调'); }, 1000); return def.promise(); }; function fn2() { var def = $.Deferred(); //执行异步操做 setTimeout(function () { console.log('执行函数2!'); def.resolve('函数2执行完毕回调'); }, 1000); return def.promise(); }; fn1().then(res => { console.log(res); //能够链式调用的核心在于返回一个Deferred对象 return fn2(); }).then(res => { console.log(res); }); //执行函数1! //函数1执行完毕回调 //执行函数2! //函数2执行完毕回调
done() && fail()
done与fail的用法与then类似,实际就是一个语法糖。
function fn1() { var def = $.Deferred(); setTimeout(function () { console.log('执行函数1!'); def.resolve('函数1执行完毕回调'); // def.reject('函数1执行失败回调'); }, 1000); return def.promise(); }; fn1().then(function (res) { console.log(res); }, function (err) { console.log(err); }); fn1().done(function (res) { console.log(res); }).fail(function (err) { console.log(err); });
always()Defferred
对象上还有一个always方法
,不管异步操做返回什么结果都会执行always
回调。
function fn1() { var def = $.Deferred(); setTimeout(function () { console.log('执行函数1!'); def.resolve('函数1执行完毕回调'); // def.reject('函数1执行失败回调'); }, 1000); return def.promise(); }; fn1().then(function (res) { console.log(res); }, function (err) { console.log(err); }).always(() => { console.log('不管成功失败都会进入这里'); });
因为Promise的出现,jQuery的Deferred对象已经不多使用了。一些其余用法在这也不一一举例了,若是有兴趣能够去官网详细了解。