一、前言
JavaScript是⼀⻔典型的异步编程脚本语⾔,在编程过程中会⼤量的出现异步代码的编写,在JS的整个发展历程中,对异步编程的处理⽅式经历了很多个时代,其中最典型也是现今使⽤最⼴泛的时代,就是Promise对象处理异步编程的时代。
异步编程是相对同步编程来说的,开发项目时,开发者总是希望,程序的执行顺利能按照编程的顺序从上至下执行,这样符合人的思维易于理解,但是现实开发中,一般都事与愿违,相信每个开发者或多或少遇到过,程序执行到某些复杂的、耗时的任务时,往往要开启异步任务去执行,这样就不会阻塞当前任务,让当前任务继续执行,当异步任务执行完后,再将异步任务执行完的结果传给当前任务使用。所以异步编程主要为提高程序整体的执行效率。
那么,Promise对象到底是什么呢?
二、上古时期的异步编程模式
长期以来,异步操作一直是JavaScript语言的痛点。在该语言的早期版本中,异步操作仅支持定义回调函数以指示异步操作已完成。异步行为的执行是一个常见的问题,通常可以通过一个充满嵌套回调函数的代码片段来解决,该代码片段通常称为“回调地狱”。
在过去的编程中JavaScript的主要异步处理⽅式,是采⽤回调函数的⽅式来进⾏处理。在前端开发过程中使⽤最多的异步流程就是AJAX请求,当系统中要求某个⻚⾯的n个接⼝保证有序调⽤的情况下就会出现下⾯的情况。看如下代码:
//获取类型数据
$.ajax({
url: '/***',
success: function(res) {
const xId = res.id;
//获取该类型的数据集合,必须等待回调执⾏才能进⾏下⼀步
$.ajax({
url: '/***',
data: {
//使⽤上⼀个请求结果作为参数调⽤下⼀个接⼝
xxId: xId,
},
success: function(res1) {
const xxId = res1.id;
//得到指定类型集合
$.ajax({
url:'/***',
data:{
//使⽤上⼀个请求结果作为参数调⽤下⼀个接⼝
xxxId: xxId,
},
success:function(res2){
//得到指定类型集合
...
}
})
}
})
}
})
看如上代码,这三个任务必须按先后顺序执⾏,并且每一个请求执行前都要先拿到上⼀个请求运⾏的结果,那么我们不得不将代码编写为以上案例代码。该写法主要是为了保证代码的严格顺序要求,这样就避免不了⼤量的逻辑在回调函数中不停的进⾏嵌套,这也是我们经常听说的“回调地狱”。这种情况在很多⼈的代码中都出现过,如果流程复杂化,在⽹络请求中继续夹杂其他的异步流程,那么这样的代码就会变得难以维护了。
再举一个我们在开发业务中常见的例子——省市区三级联动。
// 假如接口和参数如下
省级接口:http://localhost:8080/province
市级接口:http://localhost:8080/city(参数:provinceId)
区级接口:http://localhost:8080/area(参数:cityId)
先请求省级接口,获取某个省的编号,在使用省的编号,请求市级接口,获取某个市的编号,最后使用市的编号,请求区县级接口,获取区县的名称。在没有Promise之前,就会出现如下代码:
// 1.请求省级接口,获取省的编号
axios.get('http://localhost:3000/province').then(r