promise全家桶

JavaScript 中存在很多异步操作,Promise 将异步操作队列化,按照期望的顺序执行,返回符合预期的结果。可以通过链式调用多个 Promise 达到我们的目的。

promise 创建时即立即执行即同步任务,即promise里面的会立刻执行,其实resolve也会立即执行,但是它给then才能看出结果,但是then 会放在异步微任务中执行,需要等同步任务执行后才执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let promise = new Promise((resolve, reject) => {
resolve("结果成功了");
console.log('promise执行了')
});

let p2 = promise.then(resolve => {
console.log(resolve + 'then也执行了');
}
);


console.log('123')

// promise执行了 所以只要new了,虽然用字面量接收了,promise就会调用
// 123 只要then了,用字面量接收了,也会调用。
// 结果成功了then也执行了

promise 的 then、catch、finally的方法都是异步任务

如果 resolve 参数是一个 promise ,将会改变promise状态。

下例中 p1 的状态将被改变为 p2 的状态

1
2
3
4
5
6
7
8
9
10
const p1 = new Promise((resolve, reject) => {
resolve(
//p2
new Promise((s, e) => {
s("成功");
})
);
}).then(msg => {
console.log(msg);
});

当promise做为参数传递时,需要等待promise执行完才可以继承,下面的p2需要等待p1执行完成。

  • 因为p2resolve 返回了 p1 的promise,所以此时p2then 方法已经是p1 的了
  • 正因为以上原因 then 的第一个函数输出了 p1resolve 的参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("操作成功");
}, 2000);
});
const p2 = new Promise((resolve, reject) => {
resolve(p1);
}).then(
msg => {
console.log(msg);
},
error => {
console.log(error);
}
);

then 用于定义当 promise 状态发生改变时的处理,它也类似promise有两种处理方法(两个函数),then实质上也是一个promise,默认返回fulfilled(resolve了)但是也可以返回reject

1
promise.then(onFulfilled, onRejected)

then接收resolve和reject状态括号内信息,并进行操作。

promise 传向then的传递值,如果then没有可处理函数,会一直向后传递

1
2
3
4
5
6
7
8
let p1 = new Promise((resolve, reject) => {
reject("rejected");
})
.then()
.then(
null,
f => console.log(f)
);

如果 onFulfilled 不是函数且 promise 执行成功, p2 执行成功并返回相同值

1
2
3
4
5
6
7
let promise = new Promise((resolve, reject) => {
resolve("resolve");
});
let p2 = promise.then();
p2.then().then(resolve => {
console.log(resolve);
});

then 是对上个promise 的rejected 的处理,每个 then 会是一个新的promise,默认传递 fulfilled状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
new Promise((resolve, reject) => {
reject();
})
.then(//这里接收的是reject,但此then执行完了就是fulfilled
resolve => console.log("fulfilled"),
reject => console.log("rejected")
)
.then(
resolve => console.log("fulfilled"),
reject => console.log("rejected")
)
.then(
resolve => console.log("fulfilled"),
reject => console.log("rejected")
);

# 执行结果如下
ejected
fulfilled
fulfilled

如果对象中的 then 不是函数,则将对象做为值传递

1
2
3
4
5
6
7
8
9
10
11
new Promise((resolve, reject) => {
resolve();
})
.then(() => {
return {
then: "后盾人"
};
})
.then(v => {
console.log(v); //{then: "后盾人"}
});

catch

catch用于失败状态的处理函数,等同于 then(null,reject){}

  • 建议使用 catch 处理错误
  • catch 放在最后面用于统一处理前面发生的错误,它可以收集到很前面的reject
1
2
3
4
5
const promise = new Promise((resolve, reject) => {
reject(new Error("Notice: Promise Exception"));
}).catch(msg => {
console.error(msg);
});

catch 也可以捕获对 then 抛出的错误处理

1
2
3
4
5
6
7
8
9
new Promise((resolve, reject) => {
resolve();
})
.then(msg => {
throw new Error("这是then 抛出的错误");
})
.catch(() => {
console.log("33");
});

catch 也可以捕获其他错误,下面在 then 中使用了未定义的变量,将会把错误抛出到 catch

1
2
3
4
5
6
7
8
9
10
new Promise((resolve, reject) => {
resolve("success");
})
.then(msg => {
console.log(a);
})
.catch(reason => {
console.log(reason);
});
//ReferenceError: a is not defined

promise 中抛出的错误也会被catch 捕获

1
2
3
4
5
const promise = new Promise((resolve, reject) => {
throw new Error("fail");
}).catch(msg => {
console.log(msg.toString()+"后盾人");
});

finally

无论状态是resolvereject 都会执行此动作,finally 与状态无关。

1
2
3
4
5
6
7
8
9
10
11
12
const promise = new Promise((resolve, reject) => {
reject("hdcms");
})
.then(msg => {
console.log("resolve");
})
.catch(msg => {
console.log("reject");
})
.finally(() => {
console.log("resolve/reject状态都会执行");
});

resolve

使用 promise.resolve 方法可以快速的返回一个promise对象

根据值返加 promise

1
2
3
Promise.resolve("后盾人").then(value => {
console.log(value); //后盾人
});

reject

Promise.resolve 类似,reject 生成一个失败的promise

1
Promise.reject("fail").catch(error => console.log(error));

all

使用Promise.all 方法可以同时执行多个并行异步操作,比如页面加载时同进获取课程列表与推荐课程。

  • 任何一个 Promise 执行失败就会调用 catch方法
  • 适用于一次发送多个异步操作
  • 参数必须是可迭代类型,如Array/Set
  • 成功后返回 promise 结果的有序数组

allSettled

allSettled 用于处理多个promise ,只关注执行完成,不关注是否全部执行成功,allSettled 状态只会是fulfilled。即和盘托出之前的办事结果和信息。

下面的p2 返回状态为 rejected ,但promise.allSettled 不关心,它始终将状态设置为 fulfilled

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const p1 = new Promise((resolve, reject) => {
resolve("resolved");
});
const p2 = new Promise((resolve, reject) => {
reject("rejected");
});
Promise.allSettled([p1, p2])
.then(msg => {
console.log(msg);
})

// [
// { status: 'fulfilled', value: 'resolved' },
// { status: 'rejected', reason: 'rejected' }
// ]

race

使用Promise.race() 处理容错异步,和race单词一样哪个Promise快用哪个,哪个先返回用哪个。

  • 以最快返回的promise为准
  • 如果最快返加的状态为rejected 那整个promiserejected执行cache
  • 如果参数不是promise,内部将自动转为promise

下面将第一次请求的异步时间调整为两秒,这时第二个先返回就用第二人。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const hdcms = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("第一个Promise");
}, 2000);
});
const houdunren = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("第二个异步");
}, 1000);
});
Promise.race([hdcms, houdunren])
.then(results => {
console.log(results);
})
.catch(msg => {
console.log(msg);
});

async/await

使用 async/await 是promise 的语法糖?!,可以让编写 promise 更清晰易懂,也是推荐编写promise 的方式。

  • async/await 本质还是promise,只是更简洁的语法糖书写
  • async/await 使用更清晰的promise来替换 promise.then/catch 的方式

async

下面在 hd 函数前加上async,函数将返回promise,我们就可以像使用标准Promise一样使用了。

△加async的函数不会立即执行,它可以返回resolve、reject(),也可以返回一个信息;如果有await在等此函数,那就会执行了——await还有调用它的意思,不只用来接收。

1
2
3
4
5
6
7
async function hd() {
return "houdunren.com";//可以直接返回信息
}
console.log(hd());
hd().then(value => {
console.log(value);
});

如果有多个await 需要排队执行完成,我们可以很方便的处理多个异步队列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
async function hd(message) {
return new Promise(resolve => {
setTimeout(() => {
resolve(message);//也可以返回resolve
}, 2000);
});
}
async function run() {
let h1 = await hd("后盾人");//await接收信息
console.log(h1);
let h2 = await hd("houdunren.com");
console.log(h2);
}
run();

await

使用 await 关键词后会等待promise 完

  • await 后面一般是promise,如果不是直接返回
  • await 必须放在 async 定义的函数中使用
  • await 用于替代 then 使编码更优雅

下例会在 await 这行暂停执行,直到等待 promise 返回结果后才继执行。

1
2
3
4
5
6
7
8
9
10
async function hd() {
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("houdunren.com");
}, 2000);
});
let result = await promise;
console.log(result);
}
hd()

await调用async:有时需要多个await 同时执行,有以下几种方法处理,下面多个await 将产生等待

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
async function p1() {
return new Promise(resolve => {
setTimeout(() => {
console.log("houdunren");
resolve();
}, 2000);
});
}
async function p2() {
return new Promise(resolve => {
setTimeout(() => {
console.log("hdcms");
resolve();
}, 2000);
});
}
async function hd() {
await p1();
await p2();
}
hd();

// 二秒后:houdunren
// 四秒后:hdcms
//如果没有两个await,将不会执行async

一般await后面是外部其它的promise对象

1
2
3
4
5
6
7
8
9
10
11
12
13
async function hd() {
return new Promise(resolve => {
setTimeout(() => {
resolve("fulfilled");
}, 2000);
});
}
async function run() {
let value = await hd();
console.log("houdunren.com");
console.log(value);
}
run();