目录
1、在我们同时定义三个定时器程序时,他们的触发顺序是按照定时器设置的时间里来进行排序,即如下程序的执行顺序与逻辑顺序相反
在这个函数中有两个参数(resolve,rejected)(解决,拒绝)
(2)fulfilled 或 resolved(成功):调用 resolve 函数
(3)rejected(失败):调用 rejected 函数
(1)then():该方法用于指定Promise对象的状态为 fulfilled 或 resolved 时的回调函数
(2)catch():该方法为then()方法的语法糖,用于指定当Promise对象状态变为rejected(失败)时的回调函数。
(3)finally():无论Promise对象状态如何,都会执行的回调函数。它通常用于清理操作,例如关闭文件、释放资源等。
1、构造一个函数来接收操作,将需要进行的操作和事件作为参数传入
3、 完成参数的传入,为了保证顺利运行,回调函数的结果应该为
6、此时 Promise 状态为 Pending(准备)状态,在没有对其进行输出时不会改变状态
7、由于我们的函数使用的是then()方法,所以我们将成功状态返回Promise来完成状态转换
如果需要在ajax请求中使用回调地域。只需要在我们返回函数中去嵌套一个回调函数即可
将该段代码封装为一段函数,并对函数使用async,await 返回的结果就是 priomise 中then的数据
回调地狱:多层嵌套的回调函数导致的代码难以阅读和维护的情况
回调地域:使用一些编程技巧或设计模式来避免回调地狱的情况,使异步代码更加简洁、易读和易维护
一、回调地狱
了解使用回调地域的前置情况
同步:程序从上到下执行按照顺序执行
缺点:顺序执行比较慢
优点:数据较为安全
异步:多个功能并发执行
缺点:数据不安全
优点:执行效率快
回调地域的使用就是为了解决异步转为同步的操作
这里引申一个ES6常用的三阶段考题
1、let,const,var的区别
2、箭头函数和普通函数的区别以及特点
3、promise的理解(即使用promise来解决回调地狱)
回调地狱的具体使用情况
1、在我们同时定义三个定时器程序时,他们的触发顺序是按照定时器设置的时间里来进行排序,即如下程序的执行顺序与逻辑顺序相反
function open() {
console.log("打开");
}
function inside() {
console.log("放入");
}
function close() {
console.log("关闭");
}
//将这三个程序改为定时器
setTimeout(() => {
console.log("打开");
},3000)
setTimeout(() => {
console.log("放入");
},2000)
setTimeout(() => {
console.log("关闭");
},1000)
在此我们引申一个简便写法(函数套函数)
由于在定时器中,我们的形参一般为函数+时间,当我们再调用函数的时候,我们就可以将前半部分的函数简写为一个函数调用
setTimeout(() => { callback() }, time)
将函数变为调用的函数
function callback() { console.log(1); } setTimeout(callback, time);
在简写后,我们的定时器仍然输出为正常样式
2、回调地狱的使用就是为了将其改为我们可控的同步执行
function exec(callback, time)
//传入两个参数,第一个参数为函数,第二个参数为时间
{
//定时器中第一个参数就是形参的函数,第二个为形参里的具体时间
setTimeout(callback, time);
}
//写入exec()函数,这里需注意我们的函数只有两个形参,即如果需要进行回调地域
//我们需对第一个形参做再次包裹,其中包含了第一步执行的函数和下一步执行的函数
//最后写入事件,在第一步执行完之后进入第二步和第三布
exec(() => {
open();
// 才能执行
exec(() => {
inside();
// 才能执行
exec(() => {
close();
}, 1000);
}, 2000);
}, 3000);
exec(() => { open();
exec(() => {inside();
exec(() => {close();}, 1000);
}, 2000);
}, 3000);
回调地狱的样式某种程度上类似于递归,但是其主要运行逻辑如下
fn01
fn02
fn03
......
二、promise(回调地域)替代回调地狱
then(fn01) => then(fn022) => then(fn03) ......
Promise的提出主要是为了解决回调地狱(Callback Hell)的问题,即多层嵌套的回调函数导致代码难以阅读和维护。Promise提供了一种更加优雅的方式来处理异步操作,使得代码结构更加清晰,易于理解和维护。
Promise本身是同步。then()和catch()是才是异步操作
1、什么是Promise
Promise是 JavaScript 中用于处理异步操作的一种编程模式,属于回调地域。它是一个代表了某个异步操作最终完成(或失败)及其结果值的对象
Promise在本质上其实是一个构造函数,在该构造函数中只有一个参数,而该参数就是一个函数(即函数嵌套函数的操作)
在这个函数中有两个参数(resolve,rejected)(解决,拒绝)
2、Promise的三种状态
(1)Pending(准备):创建了promise对象
(2)fulfilled 或 resolved(成功):调用 resolve 函数
(3)rejected(失败):调用 rejected 函数
3、Promise原型上的三个重要实例函数
(1)then():该方法用于指定Promise对象的状态为 fulfilled 或 resolved 时的回调函数
注意:then()可以接受两个参数,第一个参数是成功的回调函数,第二个参数是可选的失败的回调函数。但在接受第二个参数时第一个参数不能为空
(2)catch():该方法为then()方法的语法糖,用于指定当Promise对象状态变为rejected(失败)时的回调函数。
语法糖(Syntactic Sugar)是指在编程语言中添加的一些语法结构,这些结构不会增加新的功能,但可以使代码编写得更简洁、更易读、更易写。语法糖的目的是为了让程序员能够更高效地表达他们的意图,而不必关心底层的实现细节。
语法糖的存在可以提高编程语言的表达能力,使得代码更加简洁、优雅。然而,过度使用语法糖可能会导致代码的可读性降低,因此在实际编程中需要适度使用。
例如javascript中的箭头函数就是一种语法糖
(3)finally():无论Promise对象状态如何,都会执行的回调函数。它通常用于清理操作,例如关闭文件、释放资源等。
使用try去捕获异常
console.log(a); try { // 捕获 可能产生问题的代码 console.log(a); }catch(err){ // console.log("捕获到了异常...",err); console.error(err); //err表示产生的问题 }
4、Promise的状态
//创建了一个新的Promise对象
let a=new Promise(
//接受该函数内的两个参数的值
(resolved, rejected) => {
//两个参数都为函数,用来改变Promise的状态
//在状态后的括号内可以进行传参
//在该处代码内由我们自定义代码的成功与失败
//后续的开发中具体的异步操作来判断成功和失败
resolved("success")
rejected("fail");
}
)
//调用这个对象
a.then(
(suc) => {
console.log("我成功了....", suc);
// 我成功了....success
},
(err) => {
console.log("我失败了....", err);
// 我失败了.... fail
}
)
5、如何判断Promise的成功和失败状态
哪些是成功的状态
1. 初始化的resolved函数:当创建一个Promise对象时,如果调用resolve函数,表示异步操作成功,Promise状态变为fulfilled。
2. 没有报错,但是没有返回值:即使没有显式返回值,只要没有报错,Promise状态仍可能为fulfilled。
3. 没有报错,但是有返回值,返回值作为下一个then的接收参数:当Promise状态为fulfilled时,可以通过then方法处理返回值,并将返回值传递给下一个then方法。
4. Promise有一个静态函数 resolve:Promise.resolve()方法用于创建一个已经成功(fulfilled)的Promise对象。
哪些是失败的状态:
1. 初始化的rejected函数:当创建一个Promise对象时,如果调用reject函数,表示异步操作失败,Promise状态变为rejected。
2. 产生异常 [默认的异常 自己写的bug]:在执行器函数中产生异常(包括默认的异常和自己写的bug),Promise状态将变为rejected。
3. 主动抛出一个异常 throw 异常对象:如果在执行器函数中主动抛出异常,Promise状态将变为rejected。
4. Promise有一个静态函数reject:Promise.reject()方法用于创建一个已经失败(rejected)的Promise对象。
具体运行解释:
- Promise有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。Promise的状态只能从pending变为fulfilled或rejected,且一旦改变就不能再次改变。
- 当创建一个Promise对象时,需要提供一个执行器函数,该函数接收两个参数:resolve和reject。resolve函数用于将Promise状态变为fulfilled,reject函数用于将Promise状态变为rejected
- 当异步操作成功时,调用resolve函数,并将成功的结果作为参数传入。这将触发then方法中注册的成功回调函数。
- 当异步操作失败时,调用reject函数,并将失败的原因作为参数传入。这将触发catch方法中注册的失败回调函数。
- Promise.resolve()和Promise.reject()是Promise的两个静态方法,分别用于创建一个已成功和已失败的Promise对象。
- then方法用于处理Promise状态变为fulfilled时的情况,catch方法用于处理Promise状态变为rejected时的情况。
6、自定义抛出的异常
通过 throw+ new + 异常对象 来构造(异常的父类都是 Error类型)
const a = 10;
if(a < 100) {
// console.error("a小于100了...");
//只是控制台打印红色字体输出
throw new Error("a小于100了...")
}
三、使用Promise来解决回调地狱
1、构造一个函数来接收操作,将需要进行的操作和事件作为参数传入
function exec(fn, time) {
}
exec(open, 3000)
2、理解Promise的运行样式
fn1()=> fn2 () => fn3()
3、 完成参数的传入,为了保证顺利运行,回调函数的结果应该为
exec(open, 3000).then(() => exec(in1, 2000)).then(() => exec(close, 1000))
4、构造函数需要有一个返回值,该返回值为Promise对象
function exec(fn, time) {
return new Promise((resolve) => {
}, time)
})
5、通过定时器去完成同步操作
function exec(fn, time) {
return new Promise((resolve) => {
setTimeout(() => {
fn()
}, time)
})
6、此时 Promise 状态为 Pending(准备)状态,在没有对其进行输出时不会改变状态
7、由于我们的函数使用的是then()方法,所以我们将成功状态返回Promise来完成状态转换
function exec(fn, time) {
return new Promise((resolve) => {
setTimeout(() => {
fn()
resolve()
}, time)
})
}
exec(open, 3000).then(() => exec(in1, 2000)).then(() => exec(close, 1000))
四、async
async:false是一个用于 XMLHttpRequest 对象的属性,用于设置请求是否异步执行。该这是默认为true,当设置为false时,请求将以同步方式执行,即浏览器会等待服务器响应完成后才会继续执行后续的代码。
然而,在现代的 JavaScript 开发中,通常推荐使用异步操作,因为同步请求会阻塞浏览器的其他操作,导致用户体验不佳。因此,即使这行代码被注释掉了,也应该避免使用同步请求,而是采用异步请求的方式。
如果需要在ajax请求中使用回调地域。只需要在我们返回函数中去嵌套一个回调函数即可
$.ajax({
url: "http://www.phonegap100.com/appapi.php?a=getPortalList&catid=20&page=1",
// async:false,
success(data) {
console.log(data);
$.ajax({
url: "./a.txt",
success(data1) {
console.log(data1);
},
});
},
});
五、同步函数转异步函数
原理:同步函数返回了一个Promise对象 ,由于then函数是异步的,所以我们认为这个是异步函数,且这个异步函数在同步函数返回后才继续执行,所以我们默认执行顺序是该同步函数后执行异步操作
在函数前添加一个async可以将同步转异步
async function fn()
{
}
需注意在这个同步转异步函数中,我们返回的a值为Promise对象,去查看对象中的Promise状态,使用对应的方式去获取返回值
async function fn01() { return "hello promise" } let a =fn01() console.log(a);
在该状态中为resolved,我们使用then()方式来获取
async function fn01() { return "hello promise" } let a =fn01().then(item => console.log(item)) console.log(a);
六、异步函数转同步函数
使用 await+函数() 将异步函数转为同步函数
注:await需要在async中使用,单独使用会报错
const result =await fn01()
console.log(result);
将该段代码封装为一段函数,并对函数使用async,await 返回的结果就是 priomise 中then的数据
async function fn02() {
const result =await fn01()
console.log(result);
}
fn02()
简化代码
exec(open, 3000).then(() => exec(in1, 2000)).then(() => exec(close, 1000))
该段代码是对then()方法的使用,我们在此基础上可以对其使用await()方法进行简化
async function fn() { await exec(open, 3000) await exec(in1, 2000) await exec(close, 1000) } fn()
七、Promise的静态函数
resolve() | 成功 |
reject() | 失败 |
all(promise对象的数组) | 如果传来的对象都是成功的 进入到then中获取所有的成功信息,如果传来的对象有失败的 进入到catch中获取失败的第一个信息 |
race(promise对象的数组) | 只会接收第一个 如果第一个是成功 进入到then中,如果第一个是失败 进入到catch中 |
console.dir(Promise);
Promise.resolve().then(() => console.log("成功了...."))
Promise.reject().catch(() => console.log("失败了...."))
//all接收Promise对象的数组
Promise.all([
Promise.resolve("成功01"),
Promise.resolve("成功02"),
Promise.resolve("成功03"),
Promise.reject("失败01"),
Promise.reject("失败02")
]).then(reson => {
//返回打印出来成功数组
console.log(reson);
}).catch(err => {
//返回的是单个的失败
console.log(err);
})
//race接收的是单个成功或错误,且只能返回多个结果中的第一个
//不论返回的类型
Promise.race([
Promise.resolve("成功01"),
Promise.resolve("成功02"),
Promise.resolve("成功03"),
Promise.reject("失败01"),
Promise.reject("失败02")
]).then(reson => {
//返回单个成功
console.log(reson);
}).catch(err => {
//返回单个失败
console.log(err);
})