一、什么是promise,为何要用promise
Promise 对象用于表示一个异步操作的最终完成(或失败)及其结果值,是异步编程的一种解决方案。
通常,我们在写异步函数的时候,可以用一个回调函数来处理返回结果,例如:
function getData(callback) {
setTimeout(() => {
callback('hello')
}, 1000)
}
getData(result => {
console.log(result) // hello
})
但是,如果返回结果需要用于二次加载,那么我们还需要嵌套一个回调函数,这样代码就复杂起来了,如果结果需要多次处理呢,这就不得不说Promise的优点:链式结构了,直接上代码:
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
var result; // 假设result为返回的结果
if (result) {
resolve('成功')
} else {
reject('失败')
}
}, 1000)
});
myPromise
.then((success) => {
console.log(1, success)
}, (fail) => {
console.log(2, fail)
})
.catch((error) => {
console.log(3, error)
})
上面,Promise()在创建时,需要接收一个函数作为参数,一旦Promise创建成功,这个函数会立即执行。它有两个参数,而且这两个参数也都是函数,resolve是在成功(或是解决问题)时执行,reject则是失败时执行。
不论成功或是失败,Promise都会返回一个结果,而这个结果就可以通过.then()方法获取。
二、Promise的链式结构
.then() 方法需要两个参数,第一个作为Promise状态成功时resolve的回调,第二个则是状态变为失败时reject的回调。
再看上边的函数,如果result成功获取,控制台则会输出“1 成功”,否则会输出“2 失败”。
那么catch是什么情况?
其实,then方法的第二个函数也可以不写,只处理成功状态,这样的话,如果失败,则会被catch捕捉,这时控制台才会输出“3 失败”。
那么,如果.then方法写了第二个参数,是不是就不用写.catch了呢?
.catch除了会捕获reject状态,在resolve处理结果的时候,如果发生意料之外的错误,也会被catch捕获,相当于 try {} catch (e) {} 方法。
除此之外,每一个 .then() 方法还会返回一个新生成的 promise 对象,这个对象可继续调用.then方法。
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('foo');
}, 1000);
});
myPromise
.then(handleResolvedA, handleRejectedA)
.then(handleResolvedB, handleRejectedB)
.then(handleResolvedC, handleRejectedC);
由于过早地处理变为reject状态的 promise 会对之后 promise 的链式调用造成影响,因此建议用下面的方法:
myPromise
.then(handleResolvedA)
.then(handleResolvedB)
.then(handleResolvedC)
.catch(handleRejectedAny);
三、Promise的其他方法
1. Promise.all()
Promise.all() 方法接收一个 promise 的 iterable 类型(Array,Map,Set)的输入,并且只返回一个Promise实例,这是什么情况呢,看定义不如上代码:
Promise.all([10, 18, 23, 25].map(number => {
return new Promise((resolve, reject) => {
if (number > 0) {
resolve(`成功${
number}`)
} else {
reject(`失败${
number}`)
}
})
})).then((r) => {
console.log(1, r)
}, (r) => {
console.log(2, r)
})
map过后,每个方法都返回一个Promise,当全部Promise执行完的时候,就会返回一个结果。此时,控制台的输出结果是:
这是都成功的情况,如果我们改一下条件,将number > 0 改为 number < 20, 会出现怎么结果呢?
这时,Promise.all会返回第一个失败的结果,不管其他Promise是否完成。
2. Promise.any()
与Promise.all()类似,当有一个满足条件的时候,就会变成resolve状态。
如果上边的例子变成Promise.any的话,成功时(number > 20):
失败时(number > 50):
3. finally()
在 promise 结束时,不论是成功(resolve)还是失败(reject),finally()方法都会执行,可以避免同样的语句需要在 then() 和 catch() 中各写一次的情况。
myPromise.finally(function() {
// 返回状态为 (resolved 或 rejected)
});
4. race()
race()在Promise的迭代中,会返回第一个执行完的Promise的结果,不管是成功(resolve)还是失败(reject)。
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'one');
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'two');
});
Promise.race([promise1, promise2]).then((value) => {
console.log(value);
});
在这个例子中,输出结果为“two”,因为它执行的快。即使将resolve改为reject也一样,只管返回结果的速度,不管成功或是失败。