今天我说下我所理解的prosime,prosime是ES6的构造函数,里面有很多方法,我们之间打印一下promise
它里面有许多方法,等会我们会一一说到。
首先,它有什么用,我们先new 一个看看
var p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log('执行完成');
resolve('随便什么数据');
}, 2000);
});
promise的构造函数接收一个参数,是一个函数,并且有两个参数:resolve,seject,分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数。
在上面一串代码中,我们执行了一个异步操作,也就是seTimeout,2秒后,输出“执行完成”,并且调用resolve方法。
运行代码,会在2秒后输出“执行完成”,注意我在这里只是new了一个对象,并没有调用它,我们传进去的函数就已经执行了,这是一个需要注意的细节,所以我们用promise的时候要把它包在一个函数里面如:
function runAsync(){
var p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log('执行完成');
resolve('随便什么数据');
}, 2000);
});
return p;
}
runAsync()
现在你应该有疑问,这个函数是有什么用,resolve又有什么用。
我们写好的函数最后会return出一个promise对象,也就是说我们最后会得到这么一个对象,还记得我们刚开始打印的一些方法么,加上这些方法,它就会很强大。
function runAsync1(){
var p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log('执行完成');
resolve('随便一些数据');
}, 1000);
});
return p;
}
runAsync1()
.then(function(results){
console.log(results);
});
这时它会先输出执行完成,在输出随便一些数据,也就是在上面函数执行完了之后,就会执行下面then里面的函数,当然它也是可以回调方法的
function runAsync1(){
var p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log('执行完成');
resolve(function(){
alert(1234598)
});
}, 1000);
});
return p;
}
runAsync1()
.then(function(results){
results();
});
你可能会说这东西有什么用,这不就是一个回调函数么,那么问题来了,有多层回调怎么办?如果回调函数也是一个异步操作,而且执行完,也需要一个相应的回调函数怎么办?promise的优势在于,可以在then方法中继续写一个promise对象并返回,然后继续调用then的回调,好比这样
function runAsync1(){
var p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log('执行完成');
resolve('随便一些数据');
}, 1000);
});
return p;
}
function runAsync2(){
var p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log('执行完成2');
resolve('随便一些数据2');
}, 2000);
});
return p;
}
function runAsync3(){
var p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log('执行完成3');
resolve('随便一些数据3');
}, 2000);
});
return p;
}
runAsync1()
.then(function(data){
console.log(data);
return runAsync2();
})
.then(function(data){
console.log(data);
return runAsync3();
})
.then(function(data){
console.log(data);
});
它会先后输出
在then方法中,你也可以直接return数据而不是一个promise对象,在后面then中就可以接受数据啦,比如我们把上面的代码修改成这样:
runAsync1()
.then(function(data){
console.log(data);
return runAsync2();
})
.then(function(data){
console.log(data);
return '直接返回数据'; //这里直接返回数据
})
.then(function(data){
console.log(data);
});
那么输出结果就变成了
说了这么多,基本对promise对象有了基本的了解,接下来我们看看他还有什么功能,我们光用了resolve,还没有用reject,它是做什么的呢?事实上,我们前面的例子中只有“执行成功”的回调,还没有“返回失败”的回调,reject的作用就是把promise的状态置为rejected,这样我们在then中就可以捕捉到了,然后执行“失败”的回调,看一下代码
function getNumber(){
var p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
var num = Math.ceil(Math.random()*10); //生成1-10的随机数
if(num<=5){
resolve(num);
}
else{
reject('数字太大了');
}
}, 2000);
});
return p;
}
getNumber()
.then(
function(data){
console.log('resolved');
console.log(data);
},
function(reason){
console.log('rejected');
console.log(reason);
}
);
我们在函数中生成一个1--10的随机数,如果它小于等于5,那么让它在成功中输出这个数字,如果他大于5,那么让它在失败中输出“数字太大啦”,在then的方法中有两个参数,一个是成功的回调方法,一个是失败的回调方法,多次执行,它就会有时输出小于5的数字,有时输出“数字太大了”.
catch的用法
我们知道promise中除了then方法,还有catch方法,它有什么用,其实它和then的第二个参数是一样的,用来指定reject的回调,用法是这样
getNumber()
.then(function(data){
console.log('resolved');
console.log(data);
})
.catch(function(reason){
console.log('rejected');
console.log(reason);
});
效果和写在then的第二个参数里面一样,不过它还有另一个作业:在执行resolve的时候(也就是then的第一个参数)时,如果抛出异常啦(代码出错啦),那么并不会报错卡死js,而是到这个catch方法中
all的用法
promise的all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完回调。我们依旧使用上面定义好的runAsync1、runAsync2、runAsync3这3个方法,看以下代码
Promise
.all([runAsync1(), runAsync2(), runAsync3()])
.then(function(results){
console.log(results);
});
用promise的all来执行,all接收一个数组参数,里面的值最终都算返回promise对象。这样,三个异步操作的并行执行的,等到他们都执行完之后才会放到then里面。那么,三个异步操作返回的数据到哪里去啦呢?都在then里面,all会吧所有异步操作的结果放在一个数组中传给then,就是上面的results。所以上面代码输出的结果就是:
有了all,你就可以并行执行多个异步操作,并且在一个回调中处理所有的返回数据。
race的用法
all方法的效果实际上是「谁跑的慢,以谁为准执行回调」,那么相对的就有另一个方法「谁跑的快,以谁为准执行回调」,这就是race方法,这个词本来就是赛跑的意思。race的用法与all一样,我们把上面runAsync1的延时改为1秒来看一下:
Promise
.race([runAsync1(), runAsync2(), runAsync3()])
.then(function(results){
console.log(results);
});
这三个异步操作同样是并行执行的。结果你应该可以猜到,1秒后runAsync1已经执行完了,此时then里面的就执行了。结果是这样的:
这个race有什么用呢?使用场景还是很多的,比如我们可以用race给某个异步请求设置超时时间,并且在超时后执行相应的操作,代码如下:
//请求某个图片资源
function requestImg(){
var p = new Promise(function(resolve, reject){
var img = new Image();
img.onload = function(){
resolve(img);
}
img.src = 'xxxxxx';
});
return p;
}
//延时函数,用于给请求计时
function timeout(){
var p = new Promise(function(resolve, reject){
setTimeout(function(){
reject('图片请求超时');
}, 5000);
});
return p;
}
Promise
.race([requestImg(), timeout()])
.then(function(results){
console.log(results);
})
.catch(function(reason){
console.log(reason);
});
requestImg函数会异步请求一张图片,我把地址写为"xxxxxx",所以肯定是无法成功请求到的。timeout函数是一个延时5秒的异步操作。我们把这两个返回Promise对象的函数放进race,于是他俩就会赛跑,如果5秒之内图片请求成功了,那么遍进入then方法,执行正常的流程。如果5秒钟图片还未成功返回,那么timeout就跑赢了,则进入catch,报出“图片请求超时”的信息。运行结果如下: