Promise 对象用于表示一个异步操作的最终完成(或失败),及其结果值。ES6语法中,Promise 是一个对象,从它可以获取异步操作的消息。
Promise对象有以下两个特点:
- 对象的状态不受外界影响。Promise 对象代表一个异步操作,有三种状态: pending(进行中)、fulfilled(已成功)、rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
- 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种情况:从pending变为fulfilled和从pending变为rejected。只要这两种情况繁盛,状态就凝固了,不会再变了。你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(event)完全不同,事件的特点是,如果你错过了,再去监听,是得不到结果的。
eg1:
const promise = new Promise(function(resolve, reject) {
// do something
if (异步操作成功) {
resolve(value)
} else {
reject(error)
}
})
上面代码是生成一个Promise对象的实例,可以用the来指定得到resolved 和 rejected 后的回调。
promise.then(function(val){
// success
}, function(error){
// failure
})
下面是一个异步方法再 Promise 内部的例子
function timeout (ms) {
return new Promise((resolve, reject) => {
// 定时器定时执行
setTimeout(() => {
resolve('done')
}, ms)
})
}
timeout(1000).then(value => {
console.log(value)
})
Promise 新建后,就会立即执行,只是resolve根据内部调用方法设置抛出
let promise = new Promise((resolve, reject) => {
console.log('Promise')
resolve()
})
promise.then(function() {
console.log('resolved')
})
console.log('Hi!')
// Promise
// Hi
// resolved
上面代码中,Promise创建后,就立即执行,输出Promise。then是resolve之后的回调函数,将再当前脚本同步任务执行完成后才会执行。
Promise 异步加载图片
function loadImageAsync(url) {
return new Promise((resolve, reject) => {
const image = new Image()
image.src = url
image.onload = function() {
resolve(image)
}
image.onerror = function() {
reject(new Error('Could not load image'))
}
})
}
Promise 实现 Ajax 操作
const getJson = function(url) {
const promise = new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.send();
xhr.onreadystatechange = function () {
// 这步为判断服务器是否正确响应
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(xhr.responseText);
resolve(xhr.responseText)
}
}
})
return promise
}
getJson("/post.json").then(function(json) {
console.log(json)
}, function(error) {
console.log(error)
})
如果调用 resolve 函数和 reject 函数时带有参数,那么它们的参数会被传递给回调函数。
const p1 = new Promise((resolve, reject) => {
// ...
})
const p2 = new Promise((resolve, reject) => {
// ...
resolve(p1)
})
上面代码中,p1和p2都是 Promise的实例,但是 p2 的 resolve 方法将 p1作为参数,即一个异步操作的结果是返回另一个异步操作。
const p1 = new Promise(function (resolve, reject) {
setTimeout(() => {
reject(console.log('---fail----'))
}, 1000)
})
const p2 = new Promise(function (resolve, reject) {
setTimeout(() => {
resolve(p1)
}, 1000)
})
p2
.then(result => console.log(result))
.catch(error => console.log(error))
// ---fail----
Promise.prototype 上的方法
- Promise.prototype.then()
// then 返回一个新的 Promise 实例
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
return resolve('chencc')
}, 1000)
})
promise.then(resolve => {
console.log(resolve)
return 'abc'
}).then(result => {
console.log(result)
})
// 'chencc'
// 'abc'
- Promise.prototype.catch()
// Promise.prototype.catch()
// .then(null, rejection)
// .then(undefined, rejection)
const promise = new Promise((resolve, reject) => {
throw new Error('error')
})
promise.then(val => {
console.log('success')
}).catch(err => {
console.log('rejected: ' + err)
})
// rejected Error: error
// 等同于
promise.then(val => {
console.log('success')
}).then(null, err => {
console.log('rejected: ' + err)
})
// 等同于
Promise 内部错误不会影响到 Promise 外部代码,通俗说 Promise 会吃掉错误。
const someAsyncThing = function() {
return new Promise(function(resolve, reject) {
// x 未定义会报错
resolve(x + 2)
})
}
someAsyncThing().then(function() {
console.log('everything is great')
}).catch(err => {
console.log(err)
})
setTimeout(() => {console.log(123)}, 2000
// ReferenceError: x is not defined
// 123
-------------------------------------------
// 换个执行顺序就会有不同结果
someAsyncThing().catch(err => {
console.log(err)
}).then(function() {
console.log('everything is great')
})
setTimeout(() => {console.log(123)}, 2000)
// ReferenceError: x is not defined
// everything is great
// 123
- Prmoise.prototype.finally()
// finally 用于不管promise最后状态如何都会执行的操作
promise
.then(result => {})
.catch(error => {})
.finally(() => {})
Promise 构造函数上的方法
- Promise.all()
const promise = Promise.all([p1, p2, p3])
promise 的状态由 p1 p2 p3 决定
1)只有 p1 p2 p3 都变成 fulfilled,p的状态才会变为fulfilled。此时 p1 p2 p3 的返回值组成一个数组,传递给p的回调。
2)只要 p1 p2 p3 的一个被 rejected,p的状态就会变为rejected,此时第一个被 reject的实例的返回值,会传递给 p 的回调函数。
- Promise.race()
const promise = Promise.race([p1, p2, p3])
上面只要 p1 p2 p3 之中有一个状态率先发生改变,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给 p 的回调函数。
- Promise.allSettled()
const promise = [ fetch('/api1'), fetch('/api2'), fetch('/api3')]
await Promise.allSettled(promise)
removeLoadingIndicator()
上面代码内部 p1 p2 p3 是三个异步请求,只有三个请求都结束,不管成功还是失败,才会调用下面的方法移除 loading。
- Promise.any()
接收一组 Promise 实例作为参数,只要有一个变为fulfilled,包装的实例就会变成 fulfilled,如果所有的参数实例变为rejected,包装实例就会变成rejected
- Promise.resolve()
const promise = Promise.resolve($.ajax('/a.json'))
将现有对象转换为 Promise 对象
Promise.resolve('foo')
new Promise(resolve => resolve('foo'))
- Promise.reject()
const promise = Promise.reject('error')
const promise = new Promise((resolve, reject) => {
reject('error')
})
对于Promise的具体实现方式,我们后在后面开一个手写各类的系列中写一个手写Promise。