JS进阶系列文章
- 函数式编程之纯函数
- 函数式编程之柯里化
- 函数式编程之组合函数
- 详解ES6中的Class
- ES6知识点解析
- ES6新增的数据结构
- ES7知识点解析
- Proxy代理对象
- Reflect映射对象
- ES10知识点解析
- 详解ES6中的Promise(上)
Promise
Promise是异步编程的解决方案,在Promise没有出现之前,是通过回调函数来解决异步的问题。
它是一个对象,里面保存着未来才会结束的事件,可以从这里面获取异步操作的信息。
状态
Promise共有三种状态,分别是
pending进行中fulfilled完成rejected失败
你可以在任何时候获取当前promise状态,promise状态的改变只有两种可能:pending=>filfilled、pending=>rejected。当状态发送改变之后,就不会再次改变了。
例子
我们从一个例子来认识Promise吧,它是一个构造函数,用来生成Promise实例。
const p = new Promise();
Promise中需要传入一个函数,且这个函数需要接受两个参数分别是resolve函数和reject函数,resolve函数用于将Promise对象的状态从pending修改成fulfilled,并将成功的结果作为参数返回出去。resolve函数用于将Promise对象的状态从pending修改成rejected,并将错误信息作为参数返回出去。
在调用
resolve、reject函数时有传入参数,这些参数会被传递给回调函数
我们把前面的例子,加入setTimeout模拟异步操作。当msg变量的值为_island时调用resolve(),否则调用reject()。
const p = new Promise((resolve, reject) => {
const msg='_island'
setTimeout(() => {
if(msg==='_island'){
resolve("执行成功");
}else{
reject()
}
}, 2000);
});
当Promise对象生成时候,我们就可以通过.then方法,获取当前异步操作对应的结果。
p.then((result)=>{
console.log('成功的状态');
console.log(result);
},(err)=>{
console.log('失败的状态');
console.log(err);
})
// 成功的状态
// 执行成功
在调用resolve、reject方法之后,Promise的任务就完成了,后续的操作应该放在then方法里面去操作。
(建议在resolve、reject方法的前面加上return关键字)
then
Promise.then()方法是返回一个新的Promise实例(不是原来的promise实例),因此可以使用链式语法.then操作。
下面这个例子,使用了两次.then方法,在第一个回调函数中返回结果作为第二个回调函数的参数。
p.then((result)=>{
console.log('成功的状态');
console.log(result);
return result
},(err)=>{
console.log('失败的状态');
console.log(err);
}).then((result)=>{
console.log(result);
})
// 成功的状态
// 执行成功
// 执行成功
catch
Promise.catch()方法用于指定发生错误时的回调函数,它是then中的传入的第二个参数的别名。和then一样,返回一个Promise对象,后面可以继续.then,
通常,我们不在then之中定义reject回调函数,建议使用catch方法来捕捉错误。
p.then((result)=>{
console.log('成功的状态');
console.log(result);
return result
}).catch((err)=>{
console.log(err);
})
// 执行失败
finally
Promise.finally()方法,无论Promise对象最后的状态是什么样的,都会执行对应的函数。
p.then((result)=>{
console.log('成功的状态');
console.log(result);
return result
}).catch((err)=>{
console.log(err);
}).finally(()=>{
console.log('无论什么状态,我都会被执行');
})
// 执行失败
all
Promise.all()方法用于将多个Promise实例包装成一个新的Promise实例。它接收一个Promise的数组或者是一个具有Iterator接口。
下面这个例子,ps数组中包含了p1、p2、p3 三个promise实例,使用all方法包装成一个新的Promise实例。
const p1 = new Promise((resolve) => {
setTimeout(() => {
resolve("p1");
}, 2000);
});
const p2 = new Promise((resolve) => {
setTimeout(() => {
resolve("p2");
}, 3000);
});
const p3 = new Promise((resolve) => {
setTimeout(() => {
resolve("p3");
}, 1000);
});
const ps = [p1, p2, p3];
这个包装出来的Promise对象(ps)的状态由传入的p1、p2、p3的状态而决定。当这三个Promise实例的状态为fulfilled时,它们的返回值会被存放到一个数组中,返回给ps的回调函数。如果某一个Promise实例的状态为rejected时,就会把reject的实例返回值传递给ps的回调函数
Promise.all(ps).then((res) => console.log(res)); // [ 'p1', 'p2', 'p3' ]
resolve
Promise.resolve方法用于将一个对象转为Promise对象。
const obj = {
name: "_island"
};
const pobj = Promise.resolve(obj);
console.log(pobj); // Promise { { name: '_island' } }
上面这种写法相当于下面这种写法
const pobj = new Promise((resolve) => resolve(obj));
边界情况
- 如果参数是
Promise对象,则不做修改,直接返回传入的这个参数 - 如果被包装的对象中包含then方法,
Promise.resolve()方法将在包装完的这个对象之后执行对象中的then方法 - 如果传入的不是一个对象或者不带有参数,
Promise.resolve()方法将返回一个新的Promise对象,状态为resolved
reject
Promise.reject()方法用于返回一个新的Promise实例,该实例的状态为rejected。
const p = Promise.reject("报错了");
// 等价下面这一行代码
const p = new Promise((null, reject) => reject("报错了"));
搭配catch方法使用,得到参数是上面reject传入的参数。
const p = Promise.reject("报错了").catch(e=>console.log(e));
// 报错了
race
Promise.race()方法和Promise.all方法类似,同样是将多个Promise实例包装出一个新的Promise实例。
const p1 = new Promise((resolve) => {
setTimeout(() => {
resolve("p1");
}, 2000);
});
const p2 = new Promise((resolve) => {
setTimeout(() => {
resolve("p2");
}, 3000);
});
const p3 = new Promise((resolve) => {
setTimeout(() => {
resolve("p3");
}, 1000);
});
const ps=Promise.race([p1,p2,p3])
ps.then(res=>console.log(res))
// p3
上面的代码,ps的状态也是根据p1、p2、p3的状态而决定的,当这三个Promise实例中其中有一个状态发生改变时,ps的状态就会将这个实例的返回值处理给ps的回调函数,所以结果是p3(如果返回值不是Promise实例,则调用先Promise.resolve再处理)
allSettled
Promise.allSettled()方法返回一个一组已完成、已失败状态的promise实例,并带有一个对象数组,每个对象表示对应的Promise结果。(这是ES2020引入的新方法)
const p1 = new Promise((resolve) => {
setTimeout(() => {
resolve("p1");
}, 2000);
});
const p2 = new Promise((resolve,reject) => {
setTimeout(() => {
reject("p2");
}, 3000);
});
const p3 = new Promise((resolve,reject) => {
setTimeout(() => {
reject("p3");
}, 1000);
});
const ps=Promise.allSettled([p1,p2,p3])
ps.then(res=>console.log(JSON.stringify(res)))
// [
// {"status":"fulfilled","value":"p1"},
// {"status":"rejected","reason":"p2"},
// {"status":"rejected","reason":"p3"}
// ]
从上面代码的返回值可以看出返回到的是数组,里面存放着每个结果的对象,status代表promise实例的状态结果,当状态是fulfilled时,对应的属性是value,如果是rejected,则对应的是一个reason属性。
any
Promise.any()方法将多个Promise实例包装成一个新的Promise实例,只要其中某一个Promise实例返回fulfilled状态这个any方法就结束了,不会等待其他Promise实例(这是ES2021引入的新方法)
const p1 = new Promise((resolve) => {
setTimeout(() => {
resolve("p1");
}, 100);
});
const p2 = new Promise((resolve,reject) => {
setTimeout(() => {
resolve("p2");
}, 3000);
});
const p3 = new Promise((resolve,reject) => {
setTimeout(() => {
resolve("p3");
}, 1000);
});
Promise.any([p1,p2,p3]).then(res=>console.log(res))
// p1