什么是Prmoise
Promise 是异步编程的一种解决方案,比传统的解决方案—回调函数和事件—更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。
Promise对象可以理解为一次执行的异步操作,使用promise对象之后可以使用一种链式调用的方式来组织代码;让代码更加的直观。也就是说,有了Promise对象,就可以将异步操作以同步的操作的流程表达出来,避免了层层嵌套的回调函数。
Promise对象的特点
1、对象的状态不受外界影响。
Promise对象代表一个异步操作,有三种状态
- pending(执行中)
- Resolved(成功,又称Fulfilled)
- rejected(拒绝)
其中pending为初始状态,fulfilled和rejected为结束状态(结束状态表示promise的生命周期已结束)。
promise只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
2、一旦状态改变,就不会再变,任何时候都可以得到这个结果。
Promise对象的状态改变,只有两种可能:从Pending变为Resolved和从Pending变为Rejected,只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果
Promise对象的缺点:
1、无法取消Promise,一旦新建它就会立即执行,无法中途取消。
2、如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
3、当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
如果某些事件不断地反复发生,一般来说,使用 Stream 模式是比部署Promise更好的选择。
Promise的使用
1、基本用法:
(1)先new一个Promise,将Promise实例化
(2)然后在实例化的promise传两个参数,一个是成功之后的resolve,一个是失败之后的reject
(3)Promise实例生成以后,可以用then方法分别指定Resolved状态和Reject状态的回调函数。then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。
var promise = function(isReady){
return new Promise(function(resolve, reject){
// do somthing, maybe async
if (isReady){
return resolve('hello world');
} else {
return reject('failure');
}
});
}
//Promise实例生成以后,可以用then方法分别指定Resolved状态和Reject状态的回调函数。
promise(true).then(function(value){
// success,这里是resolve的回调函数
console.log(value); //hello world
}, function(err){
// failure,这里是reject的回调函数
console.log(err)
})
2、链式调用
then()方法的作用是Promise实例添加解决(fulfillment)和拒绝(rejection)状态的回调函数。then()方法会返回一个新的Promise实例,所以then()方法后面可以继续跟另一个then()方法进行链式调用。
let p = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 'success');
});
p.then(
res => {
console.log(res);
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 'success');
});
}
).then(
res => console.log(res)
);
// success
// 1000ms后
// success
3、catch方法 其实它和then的第二个参数一样,用来指定reject的回调,不过它还有另外一个作用:在执行resolve的回调(也就是上面then中的第一个参数)时,如果抛出异常了(代码出错了),那么并不会报错卡死js,而是会进到这个catch方法中。
getNumber()
.then(function(data){
console.log('resolved');
console.log(data);
console.log(someData); //此处的someData未定义
})
.catch(function(reason){
console.log('rejected');
console.log(reason);
});
如果我们不用Promise,代码运行到console就直接在控制台报错了,不往下运行了。但是在这里,进到catch方法里面去了,而且把错误原因传到了reason参数中。即便是有错误的代码也不会报错了,这与我们的try/catch语句有相同的功能。
4、all的用法
Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。Promise.all可以接收一个元素为 Promise 对象的数组作为参数,当这个数组里面所有的 Promise 对象都变为 resolve 时,该方法才会返回。(Promise.all方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。)
var p1 = new Promise(function (resolve) {
setTimeout(function () {
resolve("promise1");
}, 2000);
});
var p2 = new Promise(function (resolve) {
setTimeout(function () {
resolve("promise2");
}, 1000);
});
Promise.all([p1, p2]).then(function (result) {
console.log(result); // ["promise1", "第二个promise2"]
});
5、race的用法
promise.race也是传入一个数组,但是与promise.all不同的是,race只返回跑的快的值,也就是说result返回比较快执行的那个。
var p1 = new Promise(function (resolve) {
setTimeout(function () {
console.log(1);
resolve("promise1");
}, 2000);
});
var p2 = new Promise(function (resolve) {
setTimeout(function () {
console.log(2);
resolve("promise2");
}, 1000);
});
Promise.race([p1, p2]).then(function (result) {
console.log(result);
});
// 结果:
// 2
// promise2
// 1
可以看到,传的值中,只有p2的返回了,但是p1没有停止,依然有执行。
race的应用场景为,比如我们可以设置为网路请求超时。写两个promise,如果在一定的时间内如果成功的那个我们没有执行到,我们就执行失败的那个.
手写Promise
手写实现Promise代码:
function resolvePromise(promise2,x,resolve,reject){
//判断x是否等于promise
//promiseA+规定了一段代码,可以实现promise之间的交互
if(promise2 === x){//不能自己等待自己完成
return reject(new TypeError('循环引用'))
}
if(x != null && (typeof x === 'object' || typeof x === 'function')){
//不是null 也不是对象和函数
let called;//防止成功后再调用失败
try{//防止取then时报错
let then = x.then;
if(typeof then === 'function'){//如果是函数就认为它是promise
//call第一参数是this,后面是成功的和失败的回调
then.call(x,y=>{
if(called)return;
called = true;
resolvePromise(promise2,y,resolve,reject)//递归
},r=>{
if(called)return;
called = true;
reject(r)
})
}else{//then是个普通对象 直接成功即可
resolve(x)
}
}catch(e){
if(called)return;
called = true;
reject(e)
}
}else{//x就是个普通值
resolve()
}
}
class Promise{
constructor(executor){
this.status = 'pending';//默认等待状态
this.value = undefined;
this.reason = undefined;
this.onResolvedCb = [];//存放成功的回调
this.onRejectedCb = [];//存放失败的回调
let resolve = (data) => {
if(this.status === 'pending'){
this.value = data;
this.status = 'resolved';
this.onResolvedCb.forEach(fn=>fn());//解决异步问题
}
}
let reject = (reason) => {
if(this.status === 'pending'){
this.reason = reason;
this.status = 'rejected';
this.onRejectedCb.forEach(fn=>fn());
}
}
try{//执行时可能会发生异常
executor(resolve,reject);
}catch(e){
reject(e)
}
}
then(onFullFilled,onRejected){
//then不传参的时候
onFullFilled = typeof onFullFilled === 'function' ? onFullFilled : y => y;
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
let promise2;//链式调用
if(this.status === 'resolved'){
// onFullFilled(this.value);
promise2 = new Promise((resolve,reject)=>{
try{
let x = onFullFilled(this.value);
//看x是不是promise 是promise或者是个普通值的话 作为promise2的成功结果
resolvePromise(promise2,x,resolve,reject)
//resolvePromise可以解析x和promise之间的关系
}catch(e){
reject(e)
}
})
return promise2;//调用then后返回一个新的promise
}
if(this.status === 'rejected'){
promise2 = new Promise((resolve,reject)=>{
try{
let x = onFullFilled(this.reason);
resolvePromise(promise2,x,resolve,reject)
}catch(e){
reject(e)
}
})
return promise2;
}
if(this.status === 'pending'){//既没有成功也没有失败(先执行了then)
promise2 = new Promise((resolve,reject)=>{
this.onResolvedCb.push(()=>{//存放成功回调
try{
//还可以做其他操作
let x = onFullFilled(this.value)
resolvePromise(promise2,x,resolve,reject)
}catch(e){
reject(e)
}
})
this.onRejectedCb.push(()=>{//存放失败回调
try{
//还可以做其他操作
let x = onRejected(this.reason)
resolvePromise(promise2,x,resolve,reject)
}catch(e){
reject(e)
}
})
})
return promise2;
}
}
catch(onRejected){
return this.then(null,onRejected);
}
}
Promise.resolve = function(val){
return new Promise((resolve,reject)=>resolve(val))
}
Promise.reject = function(val){
return new Promise((resolve,reject)=>reject(val))
}
Promise.all = function(promises){
return new Promise((resolve,reject)=>{
let arr=[],i=0;
function processData(index,data){
arr[index]=data;
i++;
if(i ===promises.length){
resolve(arr)
}
}
for(let i=0;i<promises.length;i++){
promises[i].then(data=>{
processData(i,data)
},reject)
}
})
}
Promise.race = function(promises){
return new Promise((resolve,reject)=>{
for (let i = 0; i < promises.length; i++) {
promises[i].then(resolve,reject)
}
})
}
//promise 语法糖
Promise.deferred = Promise.defer = function () {
let dfd = {};
dfd.promise = new Promise((resolve,reject)=>{
dfd.resolve = resolve;
dfd.reject = reject;
})
return dfd;
}
// npm install promises-aplus-tests -g
// promises-aplus-test 文件名
module.exports = Promise;