【前端--异步编程】

🚀 作者 :“码上有前”
🚀 文章简介 :前端

往期精彩内容

【前端高频面试题–HTML篇】
【前端高频面试题–CSS上篇】
【前端高频面试题–CSS下篇】
【前端高频面试题–JS上篇】
【前端高频面试题–JS下篇】
【前端高频面试题–ES6篇】
【前端高频面试题–ES7-ES11】
【前端–异步编程】
【前端高频面试题–TypeScript篇】

【前端高频面试题–git篇】
【前端高频面试题–微信小程序篇】

【前端高频面试题–Vue基础篇】
【前端高频面试题–虚拟DOM篇】
【前端高频面试题–Vue3.0篇】
【前端高频面试题–Vuex上篇】
【前端高频面试题–Vuex下篇】
【前端高频面试题–Vue生命周期篇】
【前端高频面试题–Vue组件通信篇】
【前端高频面试题–Vue路由篇】

【前端-Vue3创建一个新项目】
【前端大屏自适应缩放】
【前端Vue3 + TS项目开发一般流程】

🍓为什么使用Promise

解决回调地狱

setTimeout(function () {
    console.log("First");
    setTimeout(function () {
        console.log("Second");
        setTimeout(function () {
            console.log("Third");
        }, 3000);
    }, 4000);
}, 1000);

虽然这段程序实现了这个功能,但是它是用 “函数瀑布” 来实现的。但是用 “函数瀑布” 实现的程序无论是维护还是异常处理都是特别繁琐,而且会让缩进格式变得非常冗赘。
现在我们用 Promise 来实现同样的功能:

new Promise(function (resolve, reject) {
    setTimeout(function () {
        console.log("First");
        resolve();
    }, 1000);
}).then(function () {
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            console.log("Second");
            resolve();
        }, 4000);
    });
}).then(function () {
    setTimeout(function () {
        console.log("Third");
    }, 3000);
});

总结: Promise不仅解决了回调地狱的问题,同时对于管理异步操作,让异步看起来像同步一样 (以同步方式写异步,其实还是异步),代码更加扁平化,使得我们可以书写复杂的异步任务变的更加优雅

🍓Promise的基本用法

  1. 语法和实例
    Promise是一个构造函数,构造函数通过new实例化对象 ,Promise 接受函数作参数。该函数是同步的并且会被立即执行,所以我们称之为起始函数
    起始函数包含两个参数 resolvereject,分别表示 Promise 成功和失败的状态。
    起始函数执行成功时,它应该调用 resolve 函数并传递成功的结果。失败时,它应该调用 reject 函数并传递失败的原因。
const p = new Promise((resolve, reject)=> {
	//要处理的事情
}
  1. state三种状态以及改变方法(调用对应函数)
  1. pending:准备,待解决,进行中
  2. fulfilled:已完成,成功
  3. rejected:已拒绝,失败

注意: 状态改变是一次性的,改了再改其他的就没有用了,pending是默认状态,且修改状态是一次性的,要么调用fulfill,要么rejected
3. result结果
由参数成功失败传入对象结果

const p = new Promise((resolve, reject)=> {
	resolve('成功的结果')
	//reject()失败的结果
}

🍓Promise的方法

Promise 构造函数返回一个 Promise 对象,该对象具有以下几个方法:

  • then:用于处理 Promise 成功状态的回调函数。
  • catch:用于处理 Promise 失败状态的回调函数。
  • finally:无论 Promise 是成功还是失败,都会执行的回调函数。
    注意: catch 方法,该方法相当于最近的 then 方法的第二个参数,指向 reject 的回调函数,另一个作用是,在执行resolve回调函数时,如果出错,抛出异常,不会停止运行,而是进入catch 方法中。 catch 只捕获最近的 then 的回调函数,前面的then的执行不成功的结果,有后面 then 的 reject 回调函数执行,如果没有后续 then 回调函数执行,则会被 catch 捕获执行
    实例
const promise = new Promise((resolve, reject) => {
  // 异步操作,我们要做的事情
  setTimeout(() => {
    if (Math.random() < 0.5) {
      resolve('success'); //如果随机数小于0.5,执行promise成功时的状态
    } else {
      reject('error');  //如果随机数大于0.5,执行promise失败时的状态
    }
  }, 1000);
});
 //promise是Promise的实例化对象
promise.then(result => {
  // 这里的result为resolve函数中传入的参数	
  console.log(result);
}).catch(error => {
// 这里的error 为reject函数中传入的参数	
  console.log(error);
});

Promise 类有 .then() .catch().finally() 三个方法,这三个方法的参数都是一个函数,.then() 可以将参数中的函数添加到当前 Promise 的正常执行序列,.catch() 则是设定 Promise 的异常处理序列,.finally() 是在 Promise 执行的最后一定会执行的序列。 .then() 传入的函数会按顺序依次执行,有任何异常都会直接跳到 catch 序列
实例:

new Promise(function (resolve, reject) {
    console.log(1111);
    resolve(2222);
}).then(function (value) {
    console.log(value);
    return 3333;
}).then(function (value) {
    console.log(value);
    throw "An error";
}).catch(function (err) {
    console.log(err);
});
//输出结果: 1111 2222 3333 An error

解析如下图:
在这里插入图片描述
resolve() 中可以放置一个参数用于向下一个 then 传递一个值,then 中的函数也可以返回一个值传递给 then。
但是,如果 then 中返回的是一个 Promise 对象,那么下一个 then 将相当于对这个返回的 Promise 进行操作,这一点从刚才的计时器的例子中可以看出来。
reject() 参数中一般会传递一个异常给之后的 catch 函数用于处理异常

注意:

  • resolve 和 reject 的作用域只有起始函数 (Promise对象的参数),不包括 then 以及其他序列;
  • resolve 和 reject 并不能够使起始函数停止运行,别忘了 return
//最上述回调地狱的代码使用Promise函数之后
print(1000, "First").then(function () {
    return print(4000, "Second");
}).then(function () {
    print(3000, "Third");
});

🍓常见的问题及回答

Q: then、catch 和 finally 序列能否顺序颠倒?
A: 可以,效果完全一样。但不建议这样做,最好按 then-catch-finally 的顺序编写程序。有利于阅读与维护

Q: 除了 then 块以外,其它两种块能否多次使用?
A: 可以,finally 与 then 一样会按顺序执行,但是 catch 块只会执行第一个,除非 catch 块里有异常。所以最好只安排一个 catch 和 finally 块。

Q: then 块如何中断?
A: then 块默认会向下顺序执行,return 是不能中断的,可以通过 throw 来跳转至 catch 实现中断。

Q: 什么时候适合用 Promise 而不是传统回调函数?
A: 当需要多次顺序执行异步操作的时候,例如,如果想通过异步方法先后检测用户名和密码,需要先异步检测用户名,然后再异步检测密码的情况下就很适合 Promise。

Q: Promise 是一种将异步转换为同步的方法吗?
A: 完全不是。Promise 只不过是一种更良好的编程风格。

Q: 什么时候我们需要再写一个 then 而不是在当前的 then 接着编程?
A: 当你又需要调用另一个异步任务的时候

🍓async与awite

以上的实例也可以使用async和awite来解决

//使用async来标记一个函数asyncFunc()
//在函数体内执行异步操作
async function asyncFunc() {
    await print(1000, "First");
    await print(4000, "Second");
    await print(3000, "Third");
}
asyncFunc();

大吃一斤!这岂不是将异步操作变得像同步操作一样容易了吗!
异步函数 async function 中可以使用 await 指令,await 指令后必须跟着一个 Promise,异步函数会在这个 Promise 运行中暂停,直到其运行结束再继续运行。
异步函数实际上原理与 Promise 原生 API 的机制是一模一样的,只不过更便于程序员阅读。处理异常的机制将用 try-catch 块实现:

async function asyncFunc() {
    try {
        await new Promise(function (resolve, reject) {
            throw "Some error"; // 或者 reject("Some error")
        });
    } catch (err) {
        console.log(err);
        // 会输出 Some error
    }
}
asyncFunc();

如果 Promise 有一个正常的返回值,await 语句也会返回它:

async function asyncFunc() {
    let value = await new Promise(
        function (resolve, reject) {
            resolve("Return value");
        }
    );
    console.log(value);
}
asyncFunc();
//输出 Return value

🍓async基本语法

asyncES7 才有的与异步操作有关的关键字,和 PromiseGenerator 有很大关联的。
语法

async function name([param[, param[, ... param]]]) { statements }
// name :函数的名称
// param: 要传递给函数的参名称
// statements : 函数体语句
// return : async 函数返回一个 Promise 对象,可以使用 then 方法添加回调函数。

实例

async function helloAsync(){
    return "helloAsync";
  }
console.log(helloAsync())  // Promise {<resolved>: "helloAsync"} Promise对象
//返回的是promise对象可以直接调用then方法
helloAsync().then(v=>{
   console.log(v);         // helloAsync
})

🍓awite

async 函数中可能会有 await 表达式,async 函数执行时,如果遇到 await 就会先暂停执行 ,等到触发的异步操作完成后,恢复 async 函数的执行并返回解析值。
await 关键字仅在 async function 中有效。如果在 async function 函数体外使用 await ,你只会得到一个
实例:

function testAwait(){
   return new Promise((resolve) => {
       setTimeout(function(){
          console.log("testAwait");
          resolve();
       }, 1000);
   });
}
 
async function helloAsync(){
   await testAwait();
   console.log("helloAsync");
 }
helloAsync();
// testAwait
// helloAsync

await 操作符用于等待一个 Promise 对象, 它只能在异步函数 async function 内部使用.
语法:[return_value] = await expression;
expression: 一个 Promise 对象或者任何要等待的值。
返回:

function testAwait (x) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(x);
    }, 2000);
  });
}
 
async function helloAsync() {
  var x = await testAwait ("hello world");
  console.log(x); 
}
helloAsync ();
// hello world

正常情况下,await 命令后面是一个 Promise 对象,它也可以跟其他值,如字符串,布尔值,数值以及普通函数。

function testAwait(){
   console.log("testAwait");
}
async function helloAsync(){
   await testAwait();
   console.log("helloAsync");
}
helloAsync();
// testAwait
// helloAsync

await针对所跟不同表达式的处理方式:

  • Promise 对象:await 会暂停执行,等待 Promise 对象 resolve然后恢复 async 函数的执行并返回解析值
  • 非 Promise 对象直接返回对应的值。

实例

async function a(){  
  console.log("1")  
   console.log("2")
}
a()
console.log("3")
//打印: 1 2 3 

使用await测试

async function a(){  
  await 1  
  console.log("1")  
  console.log("2")
}
a()
console.log("3")
//打印: 3 1 2

又一实例

function getApiData() {
    // Promise异步编程的一种解决方案
    // 第一个参数是 Promise 执行成功时的回调,第二个参数是 Promise 执行失败时的回调
    return new Promise((resolve, reject) => {
        // 模拟延迟(获取服务的数据) 
       setTimeout(() => {
            // 执行成功
            resolve({name: 'kandy', age: 99})
        }, 3000)
    })
}

let user = {}

async function getUser() {
    // 执行 
   await getApiData().then(res => {
        user = res
    })
    // await后的该代码块在此会阻塞,直到 getApiData 执行后 then 完成工作后才能继续往下执行    
    console.log('获取数据完成: ', user)
}

getUser()  // 异步执行的方法
console.log('开始获取数据:')  // 此处无阻塞(同步代码)

//结果
//开始获取数据: 
//三秒后:获取数据完成:  {name: 'kandy', age: 99}

🍉 学无止境,看到这的同学,帮忙点个赞关注支持一下呗!(* ̄︶ ̄)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码上有前

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值