Promise 对象是一个构造函数
实例化的过程是同步的,回调是异步的
const promise = new Promise(function (resolve, reject) {
// Promise 函数接受一个函数作为参数
// 参数函数 有两个函数值 resolve, reject ,也是两个函数参数
resolve() // 异步操作成功时的回调函数,并且将结果作为参数传递出去
reject() // 异步操作失败时的回调函数,并且将结果作为参数传递出去
})
Promise 函数特点
-
对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
-
一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,
状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
Promise.prototype.then 方法
Promise 实例化之后,then方法指定了 resolve 和 reject状态的回调函数
then(function (value) {
// resolve 的回调
// success
},function (error) {
// reject 的回调
// error
})
- then方法在所有同步脚本执行完毕之后执行。
- 由于then 方法返回的是一个新的Promise 实例
then(resolve(), reject())
- 因此可以采用链式写法,即then方法后面再调用另一个then方法
Promise.prototype.catch 方法
-
catch 方法是 then(null, rejection) 方法的别名
-
当then()方法指定的回调函数运行中报错时, 也会被catch方法捕获。
promise.then((val) => {
console.log('resolve: ', val)
}, (err) => {
console.log('reject: ', err)
})
// 等同于
promise.then((val) => {
console.log('resolve: ', val)
}).catch((err)=>{
console.log('reject: ', err)
})
reject(new Error('test'))
// 等同于
throw new Error('test')
- 如果resolve已完成,再抛出错误则无效(
由promise函数的状态固定了就不变了的特点导致)
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
- Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。
getJSON('/post/1.json').then((post) => {
return getJSON(post.commentURL)
}).then((comments) => {
...
}).catch(() => {
// 处理上面3个promise 函数产生的错误(getJSON 和 两个then 方法)
})
- 建议用catch()方法代替 then()方法的第二个参数捕获错误信息
Promise 内部错误不会影响外部代码
- promise 函数内部错误自己消化
“Promise 会吃掉错误”,不会影响外部代码的执行
const promise = new Promise(function (resolve, reject) {
console.log(1) // 立即执行
resolve(x + 1) // x为声明
console.log(2) // 不执行
})
setTimeout(promise.then(() => {
console.log('everything is ok')
}), 3000)
setTimeout(() => {
console.log(123)
}, 1000)
输出
// 1
// Uncaught (in promise) ReferenceError: x is not defined
// 123
上面的错误也可以在catch()中捕获
setTimeout(promise.then(() => {
console.log('everything is ok')
}).catch((err) => {
console.log(err)
}), 3000)
// ReferenceError: x is not defined
-
then() 直接报错
-
catch() 捕获错误
-
如果 catch() 方法中不在控制台输出log日志,则不影响后面代码
-
跟传统的try/catch代码块区别
- 如果没有使用catch方法指定错误处理的回调函数,Promise 对象抛出的错误不会传递到外层代码,即不会有任何反应。
unhandledRejection事件 专门监听未捕获的reject错误
Promise.prototype.finally()
Promise.prototype.all()
const p = Promise.all([p1, p2, p3])
- 只有p1、p2、p3的状态都变成fulfilled, p 的状态才会变成fulfilled
- 只要p1、p2、p3 中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
const promises = [2,3,5,7,11,13].map(function (id) {
return getJSON('/post/' + id + '.json')
})
Promise.all(promises).then((posts) => {
// ...
}).catch((reason) => {
// ...
})
- 如果作为参数的Promise实例,自己定义了catch方法,那么它一旦被rejected,并不会出发Promise.all()的catch方法。
Promise.race()
将多个Promise实例,包装成一个新的Promise实例
Promise.resolve()
将现有对象转为Promise对象
-
参数是一个Promise实例
如果参数是Promise实例,promise.resolve将原封不动的返回这个实例
-
参数是一个thenable对象
thenable对象是指具有then方法的对象,比如:
let thenable = {
then: fucntion (resolve, reject) {
resolve(42)
}
}
Promise.resolve(thenable).then((res) => {
console.log(res)
})
// 42
-
参数不具有then方法,或者根本就不是对象
Promise.resolve方法返回一个新的Promise对象,状态为resolved
-
不带有任何参数
Promise.resolve方法允许调用时不带参数,直接返回一个resolved状态的Promise对象。
如果希望得到一个Promise对象,比较方便的方法就是直接调用Promise.resolve方法
立即resolve的Promise对象,是在本轮“事件循环”(event loop)结束时,而不是在下一轮“事件循环”的开始时。
setTimeout(function () {
console.log('three')
}, 0)
Promise.resolve().then(function () {
console.log('two')
})
console.log('one')
// one
// two
// three
// setTimeout(fn, 0)在下一轮“事件循环”开始时执行
Promise.reject()
Promise.reject(reason) 方法也会返回一个新的Promise实例。该实例的状态为rejected
Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。这一点与Promise.resolve方法不一致。
const thenable = {
then(resolve, reject) {
reject('出错了');
}
};
Promise.reject(thenable)
.catch(e => {
console.log(e === thenable)
})
// true
应用
加载图片
const preloadImage = function (path) {
return new Promise((resolve, reject) => {
const image = new Image()
image.onload = resolve(path)
image.onerror = reject(path)
image.src = path
})
}