Promise 是异步编程的一种解决方案
Promise对象有以下两个特点:
1、对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)
2、一旦状态改变,就不会再变,任何时候都可以得到这个结果
ES6 规定,Promise对象是一个构造函数,用来生成Promise实例
代码示例:
const promise = new Promise(function (resolve, reject) {
// ... some code
console.log('这里的代码是同步代码,会立即执行~');
let flag = true;
// let flag = false;
if (flag) {
resolve(true);
} else {
reject(false);
}
});
Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数:
promise.then(
function (value) {
// success
// Promise对象的状态变为resolved时调用
},
function (error) {
// failure
// Promise对象的状态变为rejected时调用
}
);
function timeout(time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('done');
}, time);
});
}
timeout(2000).then((value) => {
console.log(value);
});
function loadImageAsync(url) {
return new Promise(function(resolve, reject) {
const image = new Image();
image.onload = function() {
resolve(image);
};
image.onerror = function() {
reject(new Error('Could not load image at ' + url));
};
image.src = url;
});
}
如果调用resolve函数和reject函数时带有参数,那么它们的参数会被传递给回调函数。
const p = new Promise((resolve, reject) => {
resolve('hello');
});
p.then((value) => {
console.log(value); // hello
});
当一个 Promise 实例在 resolve 方法中返回另一个 Promise 实例时,当前 Promise 的最终状态将由内部 Promise 实例的状态决定
如下示例:
p1的状态就会传递给p2,也就是说,p1的状态决定了p2的状态
如果p1的状态已经是resolved或者rejected,那么p2的回调函数将会立刻执行
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('这是p1的resolve');
// reject('这是p1的reject');
}, 1000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
// p2 resolve传递 p1 实例
resolve(p1);
}, 1000);
});
p2.then((value) => {
console.log('resolve--', value); // resolve--这是p1的resolve
}).catch((error) => {
console.log('reject--', error);
});
reject函数的参数通常是Error对象的实例,表示抛出的错误
const p = new Promise((resolve, reject) => {
reject(new Error('出错了'));
});
p.catch((error) => {
console.log('报错', error); // 报错Error{}
});
注意,调用resolve或reject并不会终结 Promise 的参数函数的执行。
new Promise((resolve, reject) => {
resolve(1);
console.log(2); // 这里仍然会执行
}).then(r => {
console.log(r);
});
// 2
// 1
(1)then方法参数:
(2)then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例),因此可以采用链式写法
getJSON("/posts.json").then(function(json) {
return json.post;
}).then(function(post) {
// ...
});
(3)当前then里面的回调函数返回的还是一个Promise对象(即有异步操作)时,这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用
function getCount(count) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(count + 1);
}, 2000);
});
}
getCount(1)
.then((val) => {
console.log(val); // 2
// 返回的还是一个Promise对象
return getCount(val);
})
.then((val) => {
console.log(val); // 3
});
(1)Promise.prototype.catch()
方法是.then(null, rejection)
或.then(undefined, rejection)
的别名,用于指定发生错误时的回调函数。
getJSON('/posts.json').then(function(posts) {
// ...
}).catch(function(error) {
// 处理 getJSON 和 前一个回调函数运行时发生的错误
console.log('发生错误!', error);
});
(2)如果 Promise 状态已经变成resolved,再抛出错误是无效的。
const promise = new Promise(function(resolve, reject) {
resolve('ok');
throw new Error('test'); // 无效
});
promise
.then(function(value) { console.log(value) })
.catch(function(error) { console.log(error) });
// ok
(3)Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。
getJSON('/post/1.json').then(function(post) {
return getJSON(post.commentURL);
}).then(function(comments) {
// some code
}).catch(function(error) {
// 处理前面三个Promise产生的错误
});
finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例
const p = Promise.all([p1, p2, p3]); // p1、p2、p3都是 Promise 实例
p的状态由p1、p2、p3决定,分成两种情况:
(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数
示例:
const p1 = new Promise(function (resolve, reject) {
resolve(1);
});
const p2 = new Promise(function (resolve, reject) {
resolve(2);
});
const p3 = new Promise(function (resolve, reject) {
resolve(3);
});
const p = Promise.all([p1, p2, p3]);
p.then((list) => {
console.log(list); // [1, 2, 3]
});
将现有对象转为 Promise 对象
Promise.resolve('foo')
等价于:
new Promise(resolve => resolve('foo'))
Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected
const p = Promise.reject('出错了');
等同于
const p = new Promise((resolve, reject) => reject('出错了'))
new Promise((resolve, reject) => {
console.log(1);
resolve();
})
.then(() => {
console.log(2);
return new Promise((resove) => {
console.log(4)
resove();
})
.then(() => {
console.log(5);
})
.then(() => {
console.log(6);
});
})
.then(() => {
console.log(3);
});
解析:
(1)外部第一个 new Promise 执行,执行完 resolve ,然后执行外部第一个 then
(2)外部第一个 then 方法里面 return 一个 Promise,这个 return 代表 外部的第二个 then 的执行需要等待 return 之后的结果
(3)执行完内部两个 then 之后,再执行 外部的第二个 then
注意:和第一题相差一个 return
// 外部 promise
new Promise((resolve, reject) => {
console.log(1);
resolve();
})
.then(() => {
// 外部第一个 then
console.log(2);
// 内部 promise
new Promise((resove) => {
console.log(4);
resove();
})
.then(() => {
// 内部第一个then
console.log(5);
})
.then(() => {
// 内部第二个then
console.log(6);
});
})
.then(() => {
// 外部第二个then
console.log(3);
});
解析:
重点: 下一个 then 的注册,需要等待上一个 then 的同步代码执行完成
执行顺序:
所以最终的顺序:
1
2
4
5
3
6
注意:内部第二个then不是链式调用
// 外部 promise
new Promise((resolve, reject) => {
console.log(1);
resolve();
})
.then(() => {
// 外部第一个 then
console.log(2);
// 内部 promise
let p = new Promise((resolve, reject) => {
console.log(4);
resolve();
});
// 内部第一个then
p.then(() => {
console.log(5);
});
// 内部第二个then,注意这里不是链式调用,这里是跟内部第一个then是同步注册的
p.then(() => {
console.log(6);
});
})
.then(() => {
// 外部第二个 then
console.log(3);
});
解析:
执行内部的 Promise 的 resolve 执行之后,两个同步 p.then 是两个执行代码语句,都是同步执行,自然是会同步注册完。
输出结果:
1
2
4
5
6
3
let p = new Promise((resolve, reject) => {
console.log(1);
resolve();
});
p.then(() => {
console.log(2);
new Promise((resolve, reject) => {
console.log(3);
resolve();
})
.then(() => {
console.log(5);
})
.then(() => {
console.log(6);
});
});
p.then(() => {
console.log(4);
});
解析:
外部的注册采用了非链式调用的写法,因此外部的 p.then 是并列同步注册的
内部的第一个 then 注册之后,就开始执行外部的第二个 then 了。然后再依次执行内部的第一个 then ,内部的第二个 then
new Promise((resolve, reject) => {
console.log(1);
resolve();
})
.then(() => {
console.log(2);
new Promise((resolve, reject) => {
console.log(4);
resolve();
})
.then(() => {
console.log(5);
})
.then(() => {
console.log(6);
});
return new Promise((resolve, reject) => {
console.log(7);
resolve();
})
.then(() => {
console.log(8);
})
.then(() => {
console.log(9);
});
})
.then(() => {
console.log(3);
});
解析:
核心:外部的第二个 then ,依赖于内部的 return 的执行结果,所以会等待 return 执行完成
最终输出:
1
2
4
7
5
8
6
9
3