Promise是ES6中新增的一个类,专门用来解决异步回调地狱的问题,异步代码同步显示出来。
回调函数的例子
//成功回调函数
function successCallback() { // 固定格式
console.log('SUCCESS')
}
//失败回调函数
function failureCallback() { // 固定格式
console.log('FAILURE')
}
function myFunc(param, success, failure) {
if (param) {
success()
} else {
failure()
}
}
myFunc(0, successCallback, failureCallback) // FAILURE
myFunc(1, successCallback, failureCallback) // SUCCESS
以上回调函数可用promise实现
var t = 0;
var promise = new Promise(function(resolve, reject) {
if (t%2 == 0) {
resolve();
} else {
reject();
}
});
promise.then(function() {
console.log('SUCCESS');
}, function(){
console.log('FAILURE');
});
运行结果:
SUCCESS
注:new了一个Promise对象,没调用它,函数就已经执行了。所以使用Promise时一般包在一个函数中,在需要时调用。
因此,上面的实例可以包在函数fn()里面,需要时就调用fn()
function fn() {
var t = 1;
var promise = new Promise(function(resolve, reject) {
if (t%2 == 0) {
console.log(1);
resolve();
console.log(1.1);
} else {
console.log(2);
reject();
console.log(2.1);
}
});
promise.then(function() {
console.log(3);
console.log('SUCCESS');
console.log(3.1);
}, function(){
console.log(4);
console.log('FAILURE');
console.log(4.1);
});
return promise;
}
fn();
运行结果:
2
2.1
4
FAILURE
4.1
Promise运行流程

function test_01() {
new Promise(function(resolve, reject) {
setTimeout(() => {
resolve('success....'),
reject('fail...')
}, 1000);
}).then(
value => {
console.log('onResolved()1', value);
}
).catch(
reason => {
console.log('onRejected()1', reason);
}
)
}
test_01();
输出结果:onResolved()1 success....
setTimeout中resolve/reject只能执行一个,要么成功、要么失败。
function test_02() {
// 产生一个成功值为1的promise对象
const p1 = new Promise(function(resolve, reject) {
resolve(1)
})
// 产生一个成功值为2的promise对象
const p2 = Promise.resolve(2);
// 产生一个失败值为3的promise对象
const p3 = Promise.reject(3);
p1.then(value => {console.log(value)})
p2.then(value => {console.log(value)})
// p3.then(null, reason => {console.log(reason)}) // 写法1
// p3.then(null, value => {console.log(value)}) // 写法2
// p3.catch(value => {console.log(value)}) // 写法3
p3.catch(reason => {console.log(reason)}) // 写法4
}
test_02();
输出结果:1 2 3
function test_01() {
new Promise(resolve => {
console.log(123);
}).then(value => {console.log(456)})
console.log("hi")
}
test_01();
执行结果:123 hi
注:then没有被执行,是因为没有resolve通知。只有得到通知才会进入微任务队列。
Promise异常捕获
Promise.prototype.catch方法是Promise.prototype.then(null, rejection)的别名,用于指定发生错误时的回调函数。
Promise对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。
getJSON("/visa.json").then(function(json) {
return json.name;
}).then(function(name) {
// proceed
}).catch(function(error) {
//处理前面任一个then函数抛出的错误
});
<script>
function test_01() {
const p = new Promise(function(resolve, reject) {
setTimeout(() => {
// resolve('success....'), // promise变为resolved 成功状态
// reject('fail...') // promise变为rejected 失败状态
throw new Error('error....') // 抛出异常,promise变为pending状态,value为'error...'
}, 1000);
});
console.log(p);
}
test_01();
</script>
先改状态,还是先改值?
function test_03() { // 常规:先执行回调函数,后改状态
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1); // 2. 改变状态(pending → resolved, 同时调用回调函数指定数据)setTimeout为宏任务
},1000)
}).then( // 1. 执行回调函数(微任务),保存当前指定的回调函数
value => {},
reason => {}
)
}
function test_04() {// 先改状态,后执行回调函数
new Promise((resolve, reject) => {
resolve(1); // 1. 改变状态(pending → resolved, 同时调用回调函数指定数据)
}).then( // 2. 后执行回调函数(微任务),异步执行回调函数
value => {},
reason => {}
)
}
Promise状态改变是不可逆的,pending → resolved之后,无法再转为其他状态。
因此,resolve / reject 只能执行一个。
Promise链式调用
- 回调地狱
- 代码难阅读
- 多个串联函数适合使用回调函数嵌套
链式Promise是指在当前promise达到fulfilled状态后,即开始进行下一个promise(后邻promise)。如何衔接当前promise和后邻promise呢?(这是这里的难点)。只要在then方法里面return一个promise就好了(得到一个promise是前提)。
注意: 一定要有返回值,否则,callback 将无法获取上一个 Promise 的结果。
(如果使用箭头函数,() => x 比 () => { return x; } 更简洁一些,但后一种保留 return 的写法才支持使用多个语句。)。
function runAsync1(){
var p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log('异步任务1执行完成');
resolve('随便什么数据1');
}, 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);
});
运行结果:
异步任务1执行完成
随便什么数据1
异步任务2执行完成
随便什么数据2
异步任务3执行完成
随便什么数据3
如果then不返回Promise对象,则后面then不再受到数据。
function runAsync1(){
var p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log('异步任务1执行完成');
resolve('随便什么数据1');
}, 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 '直接返回数据'; //这里直接返回数据
})
.then(function(data){
console.log(data);
});
运行结果:
异步任务1执行完成
随便什么数据1
异步任务2执行完成
随便什么数据2
直接返回数据
promise里面的then函数仅仅是注册了后续需要执行的代码,真正的执行是在resolve方法里面执行的,理清了这层,再来分析源码会省力的多。
链接:
(ES6 Promise 用法)
Promise设计模式 (https://zhuanlan.zhihu.com/p/42377418 (30分钟,让你彻底明白Promise原理))
Promise的实现过程,其主要使用了设计模式中的观察者模式: