首先理解一下异步和同步:
异步:
js是单线程的,只有一个主要的任务流程处理我们的js程序
把一些耗时的事情通过新开线程的方式来实现,就是采用异步方法。
异步任务有:setTimeout、setInterval、ajax,像ajax的事情还没有处理完成,也不会影响当前页面的其他行为。
同步:当前线程直接处理
异步任务一般采用回调的方式,
常常遇到问题:callback hell:回到地狱。解决办法:promise
promise:构造函数,通过promise来构建一个异步处理对象。
// var a = 1;
let p1 = new Promise ((resolve,reject)=>{
// 要执行的异步任务
/*
resolve:函数,当我们调用该函数的时候。可以把当前Promise对象的任务状态改成resolved
reject:函数,当我们调用该函数的时候,可以把当前的Promise对象的任务状态改成rejected
只要Promise的任务状态发生了变化,这个Promise对象的then方法就会被执行
*/
setTimeout(() =>{
a=10;
// setTimeout执行完之后就更改promise的状态
// resolve();//resolved
reject();//rejected
},2000);
});
p1.then(()=>{
//then方法就是Promise处理任务以后继续执行的任务,
//then方法第一个参数是用来处理成功的,第二个参数是用来处理失败的
console.log(a)
},()=>{
console.log('失败了')
})
Promise对象
基本使用
new Promise(function(resolve, reject) {
// ... 要执行的(异步)任务
})
Promise状态:[[PromiseStatus]]
- pending:初始状态,既不是成功,也不是失败状态
- fulfilled/resolved:意味着操作成功完成
- rejected:意味着操作失败
Promise状态:[[PromiseStatus]]
- resolve()函数:更改Promise对象为成功状态
- reject()函数:更改Promise对象为失败状态
then方法
任务后续处理函数,一般情况下处理某个Promise任务完成(无论是成功还是失败)的后续任务
.then(onFulfilled/onResolved, onRejected)
onFulfilled/onResolved:fulfilled/resolved状态下调用
onRejected:rejected状态下调用
Promise值:[[PromiseValue]]
任务处理完成(成功或失败),返回的值
通过 resolve()、reject() 函数传入
resolve(1)、reject(1)
onFulfilled/onResolved, onRejected 函数接收
.then(val=>console.log(val), ...)
注意:
new Promise(()=>{
setTimeout(()=>{
var a = 10;
resolve();
},2000);
}).then(()=>{
// 这样会报错,undefined,因为这里的a和setTimeout的a分别是两个函数里的a,不是同一个变量
console.log(a)
});
//问题,如何将异步任务中产生的数据扔给then()函数执行呢: // 解决方法:resolve,reject这两个函数是可以传入参数的,传入的参数将被传递给then中的函数使用 new Promise((resolve,reject)=>{ setTimeout(()=>{ var a = 10; resolve(a); },2000); }).then(v=>{ // 这样会报错,undefined,因为这里的a和setTimeout的a分别是两个函数里的a,不是同一个变量 console.log(v) });
Promise Chain
then函数执行后会返回一个新的Promise对象
- 如果then没有传入处理函数,那么会返回一个继承了上一个处理状态的 Promise 对象
new Promise((resolve,reject) =>{ reject(); }).then().then(()=>{ console.log(0) },() =>{ console.log(1) })
// 结果是打印出1
如果then传入处理函数,那么默认返回一个 fulfilled/resolved 状态的 Promise 对象
new Promise((resolve,reject) =>{ reject(); }).then(()=>{ console.log(1) },()=>{ console.log(2) }).then(()=>{ console.log(3) },() =>{ console.log(4) })
结果:2 3
如果then传入了处理函数,通过处理函数显示的return了一个新的 Promise,那么返回这个显示的 Promise 对象
new Promise((resolve,reject) =>{ reject(); }).then(()=>{ console.log(1); },()=>{ console.log(2); return new Promise((resolve,reject)=>{ reject(); }) }).then(()=>{ console.log(3) },() =>{ console.log(4) })
结果:2 4
new Promise((resolve,reject) =>{ resolve(); }) .then(() => { console.log('登录成功') //获取权限 return new Promise((resolve,reject) =>{ //如果是管理员,则成功,调用resolve() // resolve(); if(false){ resolve();//无法解决中途终止后续执行的问题 } else{ reject(); } }) },() => { console.log('登录失败') }) .then(() => { console.log('是管理员') //获取资源 return new Promise((resolve,reject) =>{ resolve(); }) },() => { console.log('不是管理员') }) .then(() => { console.log('拿到资源') },() => { console.log('不能获取资源') })
问题:
不易中途终止后续任务执行
new Promise((resolve,reject) =>{
// resolve();
reject('第一步错误')
})
.then(() => {
console.log('登录成功')
//获取权限
return new Promise((resolve,reject) =>{
//如果是管理员,则成功,调用resolve()
// resolve();
if(false){
resolve();//无法解决中途终止后续执行的问题
} else{
reject();
}
})
})
.then(() => {
console.log('是管理员')
//获取资源
return new Promise((resolve,reject) =>{
resolve();
})
})
.then(() => {
console.log('拿到资源')
}).catch(err => {//catch执行完毕之后也会返回一个成功的状态的promise,所以他会继续执行catch后面then的第一个参数
console.log(err)
});
.catch方法
处理 rejected 的情况,与 then 的第二个参数 onRejected 相同
返回一个 Promise 对象,状态默认为 fulfilled/resolved
可以捕获 catch 之前的 Promise Chain 中的任一错误(如果 Promise Chain 中的 then 没有处理的话)
all属性:
多任务处理
Promise.all(iterable)
iterable:包含多个 Promise 的迭代器对象,比如数组
当迭代器对象中的所有 Promise 状态都会 fulfilled/resolved 的时候,整体才是 fulfilled/resolved,否则就是 rejected
let p1 = new Promise((resolve,reject)=>{ setTimeout(()=>{ console.log(1) resolve(10); },2000); }) let p2 = new Promise((resolve,reject)=>{ setTimeout(()=>{ console.log(2) resolve(20); },3000); }) // all属性表示,等p1,p2任务完成之后再执行then函数, //arr表示的是p1,p2值得集合 Promise.all([p1,p2]).then(arr => { console.log(3,arr);//10,20 }) //race属性:只要p1\p2中一个执行完了就会马上执行then方法 Promise.race([p1,p2]).then(arr => { console.log(3,arr);//10 })
返回一个指定状态得promise对象
Promise.resolve(1).then((v)=>{ console.log(1) },()=> { console.log(2) })
//结果为:1
异步函数:
//await必须在异步函数中才能执行 async function fn() {//表示异步函数 var v = await getValue(10);//await表示等当前得代码执行完毕才执行下面得代码 console.log(v); //可以通过return来终止继续执行后面得代码 var v = await getValue(10);//await表示等当前得代码执行完毕才执行下面得代码 console.log(v); try{//js中可以将可能会出错的代码放到try语句中,然后用catch捕获异常的错误 var v = await getValue(200);//await表示等当前得代码执行完毕才执行下面得代码 console.log(v); }.catch(e){ console.log(e) } } function getValue(val){ return new Promise ((resolve,reject) =>{ setTimeout(()=>{ /*var a = 10; resolve(val*10);*/ if(val < 100){ resolve(val*10); } else{ reject('传入的值太大了')//浏览器会报错,可以用try解决 } },2000) }); } fn();
ES7 - async
- await 操作符
- async 函数
await 必须 在 async 函数中才能使用
await 后面可以是任意值,但是一般跟 Promise 对象
- Promise 的 resolve 方法的值就是 await 值
- Promise 的 reject 不会作为值返回,需要使用 try...catch 进行捕获
promise的缺点:首先,无法取消Promise一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。如果某些事件不断地反复发生,一般来说,使用Stream模式比promise更好。