promise then err_必考:Promise、acync进化史

c4173bbf9603877be1b3ea1e304e9197.png

2020年9月2日

《每周一题系列 》

作者:Russ

博客:掘金、知乎

点赞再看,养成习惯,每周一题系列会一直更新下去,你们的支持是我持续分享的最大动力

【目录】

1. Promise

2. async/await

【正文】

一.Promise

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。

  • 优点:
  1. 规范回调的名字和顺序
  2. 拒绝回调地狱,让代码可读性更强
  3. 很方便的捕获错误

说完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

像这种使用多层匿名函数回调的嵌套,就会很难让人读懂你的代码,而这种回调套回调(一般三到五层以上)又称为回调地狱

现在我们可以

获取用户信息()
    .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

是不是简洁易懂!!!!!!

相信你一定看出来那个简洁

下面我们来分析一下易懂。

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等方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值