![c4173bbf9603877be1b3ea1e304e9197.png](https://img-blog.csdnimg.cn/img_convert/c4173bbf9603877be1b3ea1e304e9197.png)
2020年9月2日
《每周一题系列 》
作者:Russ
博客:掘金、知乎
点赞再看,养成习惯,每周一题系列会一直更新下去,你们的支持是我持续分享的最大动力
【目录】
1. Promise
2. async/await
【正文】
一.Promise
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。
- 优点:
- 规范回调的名字和顺序
- 拒绝回调地狱,让代码可读性更强
- 很方便的捕获错误
说完Promise的优点,我们来具体说一下Promise是怎么实现的
return new Promise( function(resolve, reject) {...}
使用.then(function(result) {
},funtion(error) {
})传入成功和失败的函数
Promise对象接受两个回调函数作为参数,这两个回调函数的名字不建议更改,在.then中定义这两个回调函数。一个为成功时调用的函数,第二个为失败时调用的函数。
案例
function 获取用户信息(name){
return new Promise((resolve,reject)=>{
if(name === '发发'){
console.log('我认识发发')
resolve('发发是一个帅锅')
}else{
console.log('不认识')
reject()
}
})
}
获取用户信息('发发')
.then(
(res)=>console.log(res),
(err)=>console.log('看来他不认识发发')
)
//我认识发发
// 发发是一个帅锅
获取用户信息('琳琳')
.then(
(res)=>console.log(res),
(err)=>console.log('看来他不认识发发')
)
//不认识
// 看来他不认识发发
到这里是不是觉得Promise也不过如此,我直接写回调也能实现。
接下来就是Promise的强大之处了
JavaScript 中存在很多异步任务,Promise 将异步任务队列化,按照期望的顺序执行,返回符合预期的结果
在没有Promise之前,我们要做到这点我们只能
function 获取用户信息(){
return new Promise((resolve,reject)=>{
console.log('第一次获取用户信息')
resolve('姓名:发发')
})
}
function 打印用户信息(用户信息){
return new Promise((resolve,reject)=>{
console.log(用户信息)
resolve()
})
}
function 获取另一个用户信息(){
return new Promise((resolve,reject)=>{
console.log('第二次获取用户信息')
resolve('姓名:琳琳')
})
}
获取用户信息(function(用户信息){
console.log(用户信息)
保存用户信息(用户信息, function(){
获取另一个用户信息(function(另一个用户信息){
保存用户信息(function(){})
})
})
})
![859eb5b9c8f3f497b96a2a0304208de9.png](https://img-blog.csdnimg.cn/img_convert/859eb5b9c8f3f497b96a2a0304208de9.png)
像这种使用多层匿名函数回调的嵌套,就会很难让人读懂你的代码,而这种回调套回调(一般三到五层以上)又称为回调地狱
现在我们可以
获取用户信息()
.then(打印用户信息)
.then(获取另一个用户信息)
.then(打印用户信息)
//第一次获取用户信息
//姓名:发发
//第二次获取用户信息
!!!!!!
是不是好看多了
但是Promise也存在自己的问题,比如下面这段代码
/**
* 传入参数 n,表示这个函数执行的时间(毫秒)
* 执行的结果是 n + 200,这个值将用于下一步骤
*/
function takeLongTime(n) {
return new Promise(resolve => {
setTimeout(() => resolve(n + 200), n);
});
}
function step1(n) {
console.log(`step1 with ${n}`);
return takeLongTime(n);
}
function step2(m, n) {
console.log(`step2 with ${m} and ${n}`);
return takeLongTime(m + n);
}
function step3(k, m, n) {
console.log(`step3 with ${k}, ${m} and ${n}`);
return takeLongTime(k + m + n);
}
三个步骤,但每一个步骤都需要之前每个步骤的结果
function doIt() {
console.time("doIt");
const time1 = 300;
step1(time1)
.then(time2 => {
return step2(time1, time2)
.then(time3 => [time1, time2, time3]);
})
.then(times => {
const [time1, time2, time3] = times;
return step3(time1, time2, time3);
})
.then(result => {
console.log(`result is ${result}`);
console.timeEnd("doIt");
});
}
doIt();
有没有感觉有点复杂的样子?那一堆参数处理,就是 Promise 方案的死穴—— 参数传递太麻烦了,看着就晕!
接下来就要隆重推出今天的大BOOS了
二.async/await
从最早的回调函数,到 Promise 对象,再到 Generator 函数,每次都有所改进,但又让人觉得不彻底。它们都有额外的复杂性,都需要理解抽象的底层运行机制。
异步I/O不就是读取一个文件吗,干嘛要搞得这么复杂?异步编程的最高境界,就是根本不用关心它是不是异步。
async 函数就是隧道尽头的亮光,很多人认为它是异步操作的终极解决方案。(--阮一峰)
下面就让我们用写同步代码的方式来实现上面的例子
async function doIt() {
console.time("doIt");
const time1 = 300;
const time2 = await step1(time1);
const time3 = await step2(time1, time2);
const result = await step3(time1, time2, time3);
console.log(`result is ${result}`);
console.timeEnd("doIt");
}
doIt();
// c:vartest>node --harmony_async_await .
// step1 with 300
// step2 with 800 = 300 + 500
// step3 with 1800 = 300 + 500 + 1000
// result is 2000
// doIt: 2907.387ms
![77fc8523fd641cf2758d896aee9e4dd8.png](https://img-blog.csdnimg.cn/img_convert/77fc8523fd641cf2758d896aee9e4dd8.png)
是不是简洁易懂!!!!!!
相信你一定看出来那个简洁
下面我们来分析一下易懂。
async
在 hd
函数前加上async,函数将返回promise,我们就可以像使用标准Promise一样使用了。
async function hd() {
return "houdunren.com";
}
console.log(hd());
hd().then(value => {
console.log(value);
});
await
简化then,特别是正常处理的时候
可以理解为 async wait
await 表达式会暂停当前 async function
的执行,等待 Promise 处理完成。若 Promise 正常处理(fulfilled),其回调的resolve函数参数作为 await 表达式的值,继续执行 async function
。
async function hd(message) {
return new Promise(resolve => {
setTimeout(() => {
resolve(message);
}, 2000);
});
}
async function run() {
let h1 = await hd("Russ");
console.log(h1);
let h2 = await hd("真帅");
console.log(h2);
}
run();
//Russ
//真帅
若 Promise 处理异常(rejected),await 表达式会把 Promise 的异常原因抛出。
async function myFunction() {
try {
await somethingThatReturnsAPromise();
} catch (err) {
console.log(err);
}
}
实际运用场景
//声明RequestOptions类型
export declare type RequestOptions = {
body?: BodyInit | null;
cache?: RequestCache;
credentials?: RequestCredentials;
headers?: HeadersInit;
integrity?: string;
keepalive?: boolean;
method?: 'POST' | 'GET' | 'PUT' | 'DELETE';
mode?: RequestMode;
redirect?: RequestRedirect;
referrer?: string;
referrerPolicy?: ReferrerPolicy;
signal?: AbortSignal | null;
window?: any;
data?: string | {
[key: string]: any;
};
quiet?: boolean;
isGlobal?: boolean;
dataType?: 'json' | 'text';
ctx?: Ctx;
timeout?: number;
abortRef?: (abort: () => void) => void;
} & {
[key: string]: any;
};
//声明request
export declare function request(url: string, options?: RequestOptions): Promise<any>;
//发起异步请求
async function adminApproveReturn(data) {
return await request('/api/trade/jumax/reverse/returned/admin/audit-pass', {
data,
method: 'PUT',
});
}
//async函数返回的是一个promise函数
//处理请求结果
adminApproveReturn(data).then(() => {
Modal.success({ title: "操作成功", content: tip}); //操作成功弹窗
refreshData(); //更新数据函数
}
总结
async 是异步操作终极解决解决方案。
如果异步任务间没有关联建议用Promise,还可以了解一下Promise.all,Promise.race等方法