一、Promise是什么?
-
ECMAscript 6 原生提供了 Promise 对象
-
采用console.log(Promise)看一下它的结构组成
可以看出,Promise是一个构造函数;
它有resolve,reject,race等静态方法;
它的原型(prototype)上有then,catch方法;
因此只要作为Promise的实例,都可以共享并调用Promise.prototype上面的方法(then,catch)
二、Promise的使用
Promise的使用语法
new Promise(function(resolve,reject){}/**excutor**/);
在实例化Promise时需要传入一个函数excutor作为参数,
并且在Promise构造函数执行时同步执行
- 实例1
new Promise((resolve,reject)=>{
// 定时器,1秒后执行
setTimeout(()=>console.log("执行操作"),1000);
})
可以看出1秒后,在控制台输出了相应结果,这说明:
在实例化Promise对象的过程中,作为参数的excutor函数也会执行
excutor函数还有两个参数resolve和reject,
其实这两个参数也是函数,在excutor执行时被调用
三、resolve和reject的具体用法
0. 首先我们来看看Promise的几种状态:
- pending: 初始状态,成功或失败状态
- fulfilled: 意味着操作成功完成
- rejected: 意味着操作失败
- 当我们在excutor函数中调用resolve方法时,Promise的状态就变成fulfilled,即操作成功状态,当Promise状态为fullfilled状态时执行then方法里的操作。
- 注意了,then方法里面有两个参数***onfulfilled***(Promise为fulfilled状态时执行) 和***onrejected***(Promise为rejected状态时执行)。
1. resolve的用法
- 首先,实例化Promise
- 然后,用Promise的实例调用then方法
const ps = new Promise((resolve, reject)=> {
setTimeout(()=>{
console.log('执行操作');
resolve('这是数据');
}, 1000);
});
ps.then((data)=> {
console.log(data);
console.log('这是成功操作');
});
- 控制台结果
调用resolve方法后,Promise变为操作成功状态(fulfilled),执行then方法里面onfulfilled里的操作。
其实then里面的函数就是我们平时所说的回调函数,只不过在这里只是把它分离出来而已。
2. reject的用法
就是调用reject方法后,Promise状态变为rejected,即操作失败状态,此时执行then方法里面onrejected操作。
上面我们提到了then方法有两个参数,一种是Promise状态为fulfilled时执行 (onfullfilled),一种是Promise状态为rejected时执行(onrejected)
var ps = new Promise((resolve, reject)=> {
let flag = false;
if(flag){
resolve('这是数据');
}else{
reject('这是数据');
}
});
ps.then((data)=> {
//状态为fulfilled时执行
console.log(data);
console.log('这是成功操作');
},(reason)=> {
//状态为rejected时执行
console.log(reason);
console.log('这是失败的操作');
});
3. catch方法
除了then方法外,Promise原型上还有另外一个叫catch的方法。
其实跟then方法中的第二个参数一样,就是在Promise状态为rejected时执行,then方法捕捉到Promise的状态为rejected,就执行catch方法里面的操作
var ps = new Promise((resolve, reject)=> {
let flag = false;
if(flag){
resolve('这是数据');
}else{
reject('这是数据');
}
});
ps.then((data)=> {
//状态为fulfilled时执行
console.log(data);
console.log('这是成功操作');
}).catch((reason))=> {
//状态为rejected时执行
console.log(reason);
console.log('这是失败的操作');
});
执行结果和上面reject用法的例子一样
四、为什么会有promise,他的作用是什么?
- Promise是异步编程的一种解决方案
- promise主要是为了解决js中多个异步回调难以维护和控制的问题。
例如: (回调地狱问题)
回调函数的嵌套太多,使代码的可读性和可维护性都大大降低
嵌套太多的一个例子
取4个定时器,设置延迟时间都为1s,然后每隔1s依次在控制台输出1,2,3,4…
setTimeout( ()=> {
console.log('1');
setTimeout( ()=> {
console.log('2');
setTimeout( ()=> {
console.log('3');
setTimeout( ()=> {
console.log('4');
}, 1000);
}, 1000);
}, 1000);
}, 1000);
如果我们使用Promise去实现这个效果,虽然可能代码不会减少,甚至更多,但是却大大增强了其可读性和可维护性
采用Promise来实现,避免了层层嵌套的回调函数
function getStr(param) {
return new Promise( (resolve, reject)=> {
setTimeout( ()=> {
resolve(param);
}, 1000);
});
}
getStr('1').then( (data)=> {
console.log(data);
return getStr('2');
}).then( (data)=> {
console.log(data);
return getStr('3');
}).then( (data)=> {
console.log(data);
return getStr('4');
}).then( (data)=> {
console.log(data);
})
将得到Promise实例的过程封装成一个函数getStr,并返回一个Promise实例,
再用实例去调用相应的then方法,
在每个then方法中通过return得到下一级的Promise实例,
然后再去调用then方法执行里面的操作,
再返回下一个Promise对象。
链式调用,虽然代码量增加了,但比起前面的层层嵌套,显然这种方式使得代码更易读更易维护
五、Promise的缺点
Promise 有一些缺点。
首先,无法取消 Promise,一旦新建它就会立即执行,无法中途取消。
其次,如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。
第三,当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
六、推荐
为了防止不可预知的bug,在生产项目中最好还是不要使用原生的或者自己编写的Promise(目前为止并不是所有浏览器都能很好的兼容ES6),而是使用已经较为成熟的有大量小伙伴使用的第三方Promise库,推荐一个—— Bluebird
浏览器兼容性