什么是 promise
在控制台输入 console.dir(Promise)

Promise是一个构造函数,自己身上有all、reject、resolve方法,原型上有then、catch等方法。
new 一个promise出来
let p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log('执行完成');
resolve('resolve 的数据');
}, 2000);
});
- Promise 的构造函数接收一个参数,是函数,并且传入两个参数:resolve,reject。
- resolve 表示异步操作执行成功后的回调函数。
- reject 表示异步操作执行失败后的回调函数。
- 其实这里用“成功”和“失败”来描述并不准确,按照标准来讲,resolve 是将 Promise 的状态置为fullfiled,reject 是将 Promise 的状态置为rejected。
上述代码的执行结果是,在2秒钟之后输出“执行完成”。 但是上述代码只是new了一个对象,并没有调用它,传进去的函数就已经执行了。所以用Promise的时候一般是包在一个函数中,在需要的时候去运行这个函数:
function runPromise(){
let p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log('执行完成');
resolve('resolve的数据');
}, 2000);
});
return p;
}
runPromise();
** 在包装好的函数最后会 return 出Promise对象,也就是说,执行这个函数最后得到了一个Promise对象 **
runPromise().then(function(data){
console.log(data);
});
执行结果:会在2秒后输出“执行完成”,紧接着输出“resolve的数据”。

//一般回调函数的写法也能做到上述代码的功能
function runCallBack(callback){
setTimeout(function(){
console.log('执行完成');
callback('callback 数据');
}, 2000);
}
runCallBack(function(data){
console.log(data);
});
//如果我需要在函数里再嵌套回调函数
function runCallBack(callback){
setTimeout(function(){
console.log('执行完成');
callback('callback 第一层数据');
}, 2000);
}
runCallBack(function(data,function(data){
console.log(data);
}){
console.log(data);
callback('callback 第二层数据');
});
Promise 的优点:链式操作
即将层级操作转换为了链式操作。
但是,链式操作并不是Promise的精髓,其精髓在于可以用维护状态、传递状态的方式来使得回调函数能够及时调用,它比传递callback函数要简单、灵活的多。所以使用Promise的正确场景是这样的:
runPromise1()
.then(function(data){
console.log(data);
return runPromise2();
})
.then(function(data){
console.log(data);
return runPromise3();
})
.then(function(data){
console.log(data);
});
//三个异步操作函数
function runPromise1(){
var p = new Promise(function(resolve, reject){
setTimeout(function(){
console.log('异步任务1执行完成');
resolve('resolve数据1');
}, 1000);
});
return p;
}
function runPromise2(){
var p = new Promise(function(resolve, reject){
setTimeout(function(){
console.log('异步任务2执行完成');
resolve('resolve数据2');
}, 2000);
});
return p;
}
function runPromise3(){
var p = new Promise(function(resolve, reject){
setTimeout(function(){
console.log('异步任务3执行完成');
resolve('resolve数据3');
}, 2000);
});
return p;
}
/*
输出结果:
异步任务1执行完成
resolve数据1
异步任务2执行完成
resolve数据2
异步任务3执行完成
resolve数据3
*/
reject 用法
reject的作用就是把Promise的状态置为rejected,这样我们在then中就能捕捉到,然后执行“失败”情况的回调。
//定义一个 getNumber 函数
function getNumber(){
var p = new Promise(function(resolve, reject){
setTimeout(function(){
const number = Math.ceil(Math.random()*10); //生成1-10的随机数
if(number<=5){
resolve(number);
}else{
reject('数字太大了');
}
}, 2000);
});
return p;
}
//执行
getNumber().then(
function(data){
console.log(data);
},
function(reason){
console.log(reason);
}
);

catch 的用法
它和then的第二个参数一样,用来指定reject的回调。
getNumber()
.then(function(data){
console.log(data);
})
.catch(function(reason){
console.log(reason);
});
好处:在执行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);
});
/*
resolved
4
rejected
ReferenceError:someData is not defined(...)
*/
** 也就是说进到catch方法里面去了,而且把错误原因传到了reason参数中 **
all 的用法
Promise的all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调。 仍旧使用上面定义好的 runPromise1、runPromise2、runPromise3 这三个函数,看下面的例子:
Promise
.all([runPromise1(), runPromise2(), runPromise3()])
.then(function(results){
console.log(results);
});
/*
异步任务1执行完成
异步任务2执行完成
异步任务3执行完成
["resolve数据1","resolve数据2","resolve数据3"]
*/
/*
all方法的效果实际上是「谁跑的慢,以谁为准执行回调],即以all里面执行时间最久的函数为标准,要等最后一个函数执行完成之后才会执行then里面的。
*/
- 有了all,你就可以并行执行多个异步操作,并且在一个回调中处理所有的返回数据。
- 有一个场景是很适合用这个的,打开网页时,预先加载需要用到的各种资源如图片、flash以及各种静态文件。所有的都加载完后,我们再进行页面的初始化。
race的用法
Promise
.race([runPromise1(), runPromise2(), runPromise3()])
.then(function(results){
console.log(results);
});
/*
异步任务1执行完成
resolve数据1
异步任务2执行完成
异步任务3执行完成
*/
/*
与 all 用法一样,但是作用相反,它是以race里面执行时间最短的函数为标准,只需要执行时间最短的那个函数执行完毕,就会执行then里面的操作,所以在执行了 runPromise1()里面的操作之后立即就执行了then里面的。但是 runPromise2(), runPromise3()并不会中断执行,仍然会在1s后输出执行完成。
*/
使用场景
//请求某个图片资源
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);
});