1.JS中的一些认知
同步异步
js 是一门单线程语言,js 引擎有一个主线程(main thread)用来解释和执行 js 程序,所以JS中的代码都是串行的, 前面没有执行完毕后面不能执行
任务分为
同步任务
和异步任务
,如果所有的任务都是让主线程(main thread)来处理,如果任务很多个,就会造成线程堵塞
,进而出现界面卡顿或者假死的现象
为了防止上述的
界面卡顿或者假死的现象
,所以要使用异步任务
(比如:AJAX异步请求,定时器等操作)就会交给工作线程来处理,异步任务完成后将异步回调函数注册进任务队列
,等待主线程空闲时调用
我们常见的异步执行代码 在js中为 事件绑定的函数
和回调函数
console.log("1"); // 同步代码
setTimeout(function () { // 异步代码
console.log("2");
}, 500);
console.log("3"); // 同步代码
解释
- 主线程开始同步任务执行,执行
console.log("1");
- 然后接下来,主线程遇见一个异步操作
setTimeou
t,将改异步任务交给工作线程处理,异步任务完成之后,将回调函数注册进任务队列,等待被调用 - 继续同步任务处理,执行
console.log("3");
- 主线程空闲,调用任务队列中等待执行的回调函数,执行
console.log("2");
2.Promise
在看primise
之前我们先看一个 需求任务,从网络上加载3个资源, 要求加载完资源1才能加载资源2, 加载完资源2才能加载资源3
实现方法如下:
//定义一个请求函数
function quest(fn) {
setTimeout(function () {
fn("加载完成");
},1000);
}
//嵌套执行
quest(function (data) {
console.log(data,1);
quest(function (data) {
console.log(data,2);
quest(function (data) {
console.log(data,3);
});
});
});
从上面的代码中我满可以知道,函数层层嵌套调用,代码的可维护性和代码的阅读性比较低
为了解决上述的问题ES6中推出了Promise
2.1什么是Promise
- 它是ES6中新增的一个对象
- 可以将异步操作以同步流程来表示, 避免了回调函数层层嵌套
使用
Promise
来试试刚刚上面的 需求问题 ,一个简单的promise
的认知
//创建一个函数
function questPromise() {
return new Promise(function (resolve,reject) {
setTimeout(function () {
resolve("收到数据");
},1000);
});
}
//调用
questPromise().then(function (data) {
console.log(data,1);
return questPromise();
}).then(function (data) {
console.log(data,2);
return questPromise();
}).then(function (data) {
console.log(data,3);
})
上述的代码,
Promise
确实的解决了函数的层层嵌套问题,也用同步的方式表述了 异步的操作,接下面 我们就 详细介绍一些Promise
2.2 Promise对象的创建
- 格式:
new Promise(function(resolve, reject){});
-
resolve
和reject
对应的是回调函数
,更改Promise
的状态 -
promise对象不是异步的
,只要创建promise对象就会立马执行存放的代码
console.log("1");
let promise = new Promise(function (resolve,reject) {
console.log("2")
});
console.log("3");
//从打印的结果来看,promise代码块里面的代码是 立马执行的
2.3 Promise是如何实现 通过同步的流程来表示异步的操作的?
- promise对象是通过
状态的改变
来实现的, 只要状态发生改变就会自动触发对应的函数 - Promise对象三种状态
-
pending
: 默认状态,只要没有告诉promise任务是成功还是失败就是pending状态 -
fulfilled(resolved)
: 只要调用resolve函数, 状态就会变为fulfilled, 表示操作成功 -
rejected
: 只要调用rejected函数, 状态就会变为rejected, 表示操作失败
-
let promise = new Promise(function (resolve,reject) {
});
console.log(promise);
状态更改为 resolved
let promise = new Promise(function (resolve,reject) {
//回调
resolve("状态更改");
});
console.log(promise);
状态更改为 reject
let promise = new Promise(function (resolve,reject) {
// resolve("状态更改");
reject("状态更改为reject")
});
console.log(promise);
注意点: 状态一旦
改变既不可逆
,既从pending变为fulfilled, 那么永远都是fulfilled(resolve)
,既从pending变为rejected, 那么永远都是rejected
2.4 监听promise
变化的2个方法
resolved --> then()
rejected --> catch()
如果状态变为
resolved
,就会执行then
方法
let promise = new Promise(function (resolve,reject) {
resolve();
});
promise.then(function () {
console.log(promise);
});
如果状态变为
rejected
,就会执行catch
方法
let promise = new Promise(function (resolve,reject) {
// resolve();
reject();
});
promise.catch(function () {
console.log(promise);
});
2.5 then
方法的注意点
-
then
方法可以接受2个参数- 状态切换为成功时的回调
- 状态切换为失败时的回调
let promise = new Promise(function (resolve, reject) {
// resolve();
reject();
});
promise.then(function () {
console.log("成功");
},function () {
console.log("状态失败");
});
- 在修改promise状态时, 可以
传递参数给then方法中的回到函数
let promise = new Promise(function (resolve, reject) {
resolve("测试");
});
// success = resolve 函数
let success = (data)=>{
console.log(data);
}
// reject = error 函数
let error = (data)=>{
console.log(data);
}
promise.then(success,error);
// success = resolve 函数 reject = error 函数
- 同一个
promise
对象可以多次调用then
方法,当promise
对象状态变化时所有的then方法都会执行
let promise = new Promise(function (resolve, reject) {
resolve("多次调用then方法");
});
promise.then(function (data) {
console.log(data);
},function (error) {
console.log(error);
});
promise.then(function (data) {
console.log(data);
},function (error) {
console.log(error);
});
-
then方法
每次执行完毕后会返回一个新的promise对象
验证是不是返回了一个
新的promise对象
let promise = new Promise(function (resolve, reject) {
resolve("验证");
});
let p = promise.then(function (data) {
console.log(data);
});
//判断是不是 统一对象
console.log(promise == p);
- 可以通过
上一个promise对象的then方法
,给下一个promise对象的then方法传递参数
注意:无论是在
上一个promise对象成功的回调还是失败的回调传递的参数
, 都会传递给下一个promise对象成功的回调
let promise = new Promise(function (resolve, reject) {
resolve("data");
// reject("失败");
});
let p2 = promise.then(function (data) {
console.log(data,"1111");
//给p2中的then方法 传递参数
return "data2222";
},function (data) {
console.log(data,"1111");
return "失败222";
});
//p2调用then方法
p2.then(function (data2) {
console.log(data2,"2222");
},function (data2) {
console.log(data2,"222--");
})
- 如果
then方法返回的是一个Promise对象,
那么会将返回的Promise对象的执行结果中的值,传递给下一个then方法
let promise = new Promise(function (resolve, reject) {
resolve("111111");
});
let p2 = new Promise(function (resolve, reject) {
resolve("p2状态更改成功的回调");
});
let pp = promise.then(function (data) {
console.log(data);
//返回p2
return p2;
},function (data) {
console.log(data);
return "mmmmmm";
});
//p2装改改变的参数传递给pp
pp.then(function (data) {
console.log(data,"是不是p2");
},function (data) {
console.log(data,"失败p2");
});
2.6 catch方法
- 如果需要分开监听, 也就是通过
then监听成功
通过catch监听失败
那么必须使用链式编程, 否则会报错
let promise= new Promise(function (resolve, reject) {
resolve("1111");
});
promise.then(function (data) {
console.log(data);
}).catch(function (data) {
console.log(data);
});
这就是解释了
2.4状态变化的时候reject
报错的, 那么为什么为报错呢?
- 如果
promise的状态是失败
, 但是没有对应失败的监听
就会报错 -
then方法
会返回一个新的promise
, 新的promise会继承原有promise的状态
- 如果
新的promise状态是失败
, 但是没有对应失败的监听
也会报错
let promise= new Promise(function (resolve, reject) {
reject("失败");
});
//p2 继承了promise的 reject状态
let p2 = promise.then(function (data) {
console.log(data);
});
//防止报错
p2.catch(function (data) {
console.log(data);
});
-
catch
方法可以捕获promise对象then方法中的异常
let promise = new Promise(function (resolve, reject) {
resolve("成功过");
});
promise.then(function (data) {
console.log(data);
// obj这个变量不存在
console.log(obj);
}).catch(function (error) {
console.log(error);
});
2.6 - Promise的静态方法
2.6.1 -all方法
- 返回一个
promise
对象 -
all方法
接收的是一个数组 - 数组中的多个
promise
对象,只有都成功
才会执行then方法
,并且按照添加的顺序,将所有的成功结果存放到一个数组中返回
,这个返回的数组
传给then
函数的参数 - 如果数组中不是
promise
对象就会直接执行then方法
let p1 = new Promise(function (resolve, reject) {
// resolve("111");
reject("aaa");
});
let p2 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("222");
}, 5000);
});
let p3 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("333");
}, 3000);
});
Promise.all([p1, p2, p3]).then(function (result) {
// result 是返回成功的数组
console.log("成功", result);
}, function (err) {
console.log("失败", err);
});
使用场景: 批量加载, 要么一起成功, 要么一起失败
2.6.2 race
方法
- 返回一个
promise
对象 -
race()
参数是接收的是一个数组,数组中存放的promise
对象,这些promise
对象谁先返回就听谁的,后返回被抛弃,意思就说,这些promise对象
哪一个状态先发生变化,就返回哪一个
一般应用在 接口API的调试,超时处理
let p1 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("p1状态变化");
},300);
});
let p2 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("p2状态变化");
},200);
});
Promise.race([p1,p2]).then(function (data) {
console.log("第一个",data);
}).catch(function (e) {
console.log(e);
})