一,认识Promise
相信用过JS的都知道JS是单线程的,同步的函数先执行,异步的函数先加入到一个队列中等同步执行完了再执行异步函数。基于这个JS采用异步回调的方式来处理需要等待的事件,是的代码会继续执行而不用在异步处理的地方一直等待着。同时也带来一个不好的方面,如果我们有很多的回调函数, 也就是说一个回调函数里边再嵌套一个回调一层一层的嵌套,这样就很容易进入传说中的回调地狱。
注意:异步和回调不是一个东西
下面感受一下回调地狱代码的魅力:
1 async(1, function(value){ 2 async(value, function(value){ 3 async(value, function(value){ 4 async(value, function(value){ 5 async(value, function(value){ 6 async(value, final); 7 }); 8 }); 9 }); 10 }); 11 });
是挺有美感的但是阅读性很差,写法也让人感到无力,es6新出的promise对象已经es7的async await都可以解决这个问题,但是今天的主角是Promise。
Promise是异步编程的一种解决方案,可以替代传统的解决方案--回调函数和事件。ES6统一了用法,并原生提供了Promise对象。作为对象,Promise有一下两个特点:(1)对象的状态不受外界影响;(2)一旦状态改变了就不会在变,也就是说任何时候Promise都只有一种状态。Promise有三种状态,分别是:Pending(进行中),Resolved(完成),Rejected (失败)。Promise从Pending状态开始,如果成功就转到成功态,并执行resolve回调函数;如果失败就转到失败状态并执行reject回调函数。
Promise一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise 对象的状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变为 Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
二.使用Promise
resolve
,reject
,它们由JavaScript引擎提供。其中resolve
函数的作用是当Promise对象转移到成功,调用resolve并将操作结果作为其参数传递出去;reject
函数的作用是单Promise对象的状态变为失败时,将操作报出的错误作为其参数传递出去介绍一下Promise的api怎么使用:
1、Promise.resolve()的作用将现有对象转为Promise对象resolved;Promise.resolve('test')==new Promise(resolve=>resolve('test'))
2、Promise.reject()返回一个Promise对象,状态为rejected
3、Promise.prototype.then()方法接受两个参数,第一个是成功的resolved的回调,另一个是失败rejected的回调,第二个失败的回调参数可选。并且then方法里也可以返回promise对象,这样就可以链式调用了。
1 function judgeNumber(num){ 2 var promise1 = new Promise(function(resolve,reject){ 3 num =5; 4 if(num<5){ 5 resolve("num小于5,值为:"+num); 6 }else{ 7 reject("num不小于5,值为:"+num); 8 } 9 }); 10 return promise1; 11 } 12 13 judgeNumber().then( 14 function(message){ 15 console.log(message); 16 }, 17 function(message){ 18 console.log(message); 19 } 20 )
包含有两个方法,前一个执行resolve回调的参数,后一个执行reject回调的参数。
4、Promise.prototype.catch()发生错误的回调函数。
1 function judgeNumber(num){ 2 var promise1 = new Promise(function(resolve,reject){ 3 num =5; 4 if(num<5){ 5 resolve("num小于5,值为:"+num); 6 }else{ 7 reject("num不小于5,值为:"+num); 8 } 9 }); 10 return promise1; 11 } 12 13 judgeNumber().then( 14 function(message){ 15 console.log(message); 16 } 17 ) 18 .catch(function(message){ 19 console.log(message); 20 })
这个时候catch
执行的是和reject
一样的,也就是说如果Promise的状态变为reject时,会被catch捕捉到,
不过需要特别注意的是如果前面设置了reject方法的回调函数,·则catch不会捕捉到状态变为reject
的情况。catch
还有一点不同的是,如果在resolve
或者reject
发生错误的时候,会被catch
捕捉到,
这与java,c++的错误处理时一样的,这样就能避免程序卡死在回调函数中了。
5、Promise.all() // 所有的都有完成,相当于 且,适合用于所有的结果都完成了才去执行then()成功的操作。
1 let p1 =new Promise(function(resolve,reject){ 2 resolve(1); 3 }); 4 let p2 = new Promise(function(resolve,reject){ 5 resolve(2); 6 }); 7 let p3 = new Promise(function(resolve,reject){ 8 resolve(3); 9 }); 10 Promise.all([p1, p2, p3]).then(function (results) { 11 console.log('success:'+results); //success:1,2,3 12 }).catch(function(r){ 13 console.log("error"); 14 console.log(r); 15 });
6、Promise.race() // 完成一个即可,相当于 或。(这个经常用在一些图片比较多得网站)
1 //模拟请求某个图片资源 2 function requestImg(){ 3 var p = new Promise(function(resolve, reject){ 4 var img = new Image(); 5 img.onload = function(){ 6 resolve(img); 7 } 8 img.src = 'yingaxiang'; 9 }); 10 return p; 11 } 12 13 //延时函数,用于给请求计时 14 function timeout(){ 15 var p = new Promise(function(resolve, reject){ 16 setTimeout(function(){ 17 reject('图片请求超时'); 18 }, 5000); 19 }); 20 return p; 21 } 22 23 Promise 24 .race([requestImg(), timeout()]) 25 .then(function(results){ 26 console.log(results); 27 }) 28 .catch(function(reason){ 29 console.log(reason); 30 });
这样就相当于requestImg方法与timeout方法的龟兔赛跑,如果五秒内图片请求成功了那么就会进入.then中,如果五秒内请求图片不成功则将进入.catch中提示请求超时
Promise Ajax
1 function ajax(URL) { 2 return new Promise(function (resolve, reject) { 3 var req = new XMLHttpRequest(); 4 req.open('GET', URL, true); 5 req.onload = function () { 6 if (req.status === 200) { 7 resolve(req.responseText); 8 } else { 9 reject(new Error(req.statusText)); 10 } 11 }; 12 req.onerror = function () { 13 reject(new Error(req.statusText)); 14 }; 15 req.send(); 16 }); 17 } 18 var URL = "https://www.cnblogs.com/yingaxiang/"; 19 ajax(URL).then(function onFulfilled(value){ 20 document.write('内容是:' + value); 21 }).catch(function onRejected(error){ 22 document.write('错误:' + error); 23 });