Promise
Promise
,简单来说就是一个容器,里面保存着某个未来才会结束的时间(通常是一个异步操作的结果)
Promise
对象的基本语法:
new Promise((resolve,reject) => {
//.....
});
从语法上来说,Promise
是一个对象,从它可以获取异步操作的消息。
基本语法:
let p = new Promise((resolve,reject) => {
//...
resolve('success')
});
p.then(result => {
console.log(result);//success
});
Promise
对象特点和三个状态:
let p = new Promise((resolve,reject) => {
//...
resolve('success');
console.log('after resolve');
reject('error');
});
p.then(result => {
console.log(result);
});
p.catch(result => {
console.log(result);
})
运行结果:
after resolve
success
resolve
下面的语句其实是可以执行的,那么为什么reject
的状态信息在下面没有接受到呢?这就是因为Promise
对象的特点:状态的凝固。new
出一个Promise
对象时,这个对象的起始状态就是Pending
状态,在根据resolve
或reject
返回Fulfilled
状态/Rejected
状态。
Then
分别接受resolve
和reject
的信息,有三种参数形式,第三种比较“怪异”,只用来接收做reject
处理。
eg:
let p = new Promise((resolve,reject) => {
//...
let random = Math.random();//小于1大于0
if(random > 0.4) {
resolve('random > 0.4');
}else {
reject('random <= 0.4');
}
});
p.then(result => {
console.log('resolve',result);
}, result => {
console.log('reject',result);
});
我们来执行一段代码:
let p = new Promise((resolve,reject) => {
reject('reject');
});
let resultP = p.then(null,result => {
console.log(result);
});
console.log(resultP);
结果:
Promise { }
reject
js
的执行顺序就是这样,同步->异步->回调,在同步执行的时候,Promise
对象还处于pending
的状态,也说明了这个then
返回的是一个Promise
对象。
而且必须在then
里面给一个返回值,才能继续调用,否则undefined
。
eg:
let p = new Promise((resolve,reject) => {
reject('error');
});
let resultP = p.then(null,result => {
console.log(result);
return 123;
});
// console.log(resultP);
resultP.then(tmp => {
console.log(tmp);
})
结果:
error
123
catch
eg:
let p = new Promise((resolve,reject) => {
reject('error');
});
p.catch(result => {
console.log(result);
})
那这个catch
的返回值是什么呢:
和上面then
是一样的。
Promise.resolve()
// let p1 =Promise.resolve(123);
let p1 =Promise.resolve({
name:'xixi',age:'xxxx'});
p1.then(result => {
console.log(result);
});
如果是Promise
对象呢,直接返回
let p = new Promise((resolve,reject) => {
setTimeout(() => {
resolve('success');
},500);
});
let pp = Promise.resolve(p);
pp.then(result => {
console.log(result);
});
console.log(pp == p);
结果:
true
success
Promise.reject()
let p = Promise.reject(123);
console.log(p);
p.then(result => {
console.log(result);
}).catch(result => {
console.log('catch',result);
})
结果:
Promise { 123 }
catch 123
Promise.all()
let p1 = Promise.resolve(123);
let p2 = Promise.resolve('hello');
let p3 = Promise.resolve('success');
Promise.all([p1,p2,p3]).then(result => {
console.log(result);
})
结果:
[ 123, 'hello', 'success' ]
成功之后就是数组类型,当所有状态都是成功状态才返回数组,只要其中有一个的对象是reject
的,就返回reject
的状态值。
eg:
let p1 = Promise.resolve(123);
let p2 = Promise.resolve('hello');
let p3 = Promise.resolve('success');
let p4 = Promise.reject('error');
// Promise.all([p1,p2,p3]).then(result => {
// console.log(result);
// });
Promise.all([p1,p2,p4]).then(result => {
console.log(result);
}).catch(result => {
console.log(result);
});
结果:
error
又一个eg:
//用sleep来模仿浏览器的AJAX请求
function sleep(wait) {
return new Promise((res,rej) => {
setTimeout(() => {
res(wait);
},wait);
});
}
let p1 = sleep(500);
let p2 = sleep(500);
let p3 = sleep(1000);
Promise.all([p1,p2,p3]).then(result => {
console.log(result);
//.....
//loading
});
Promise.race
和all
同样接受多个对象,不同的是,race()
接受的对象中,哪个对象返回的快就返回哪个对象,就如race
直译的赛跑这样。如果对象其中有reject
状态的,必须catch
捕捉到,如果返回的够快,就返回这个状态。race
最终返回的只有一个值。
eg:
//用sleep来模仿浏览器的AJAX请求
function sleep(wait) {
return new Promise((res,rej) => {
setTimeout(() => {
res(wait);
},wait);
});
}
let p1 = sleep(500);
let p0 = sleep(2000);
Promise.race([p1,p0]).then(result => {
console.log(result);
});
let p2 = new Promise((resolve,reject) => {
setTimeout(()=>{
reject('error');
},1000);
});
Promise.race([p0,p2]).then(result => {
console.log(result);
}).catch(result => {
console.log(result);
});
500
error
为什么说安静,一个例子,Pormise
内部的错误外界用try-catch
捕捉不到
eg:
try {
let p = new Promise((resolve, reject) => {
throw new Error("I'm error");
// reject(new Error("I'm Error"));
});
}catch(e) {
console.log('catch',e);
}
结果什么都没打印。
但是抛出的错误可以通过catch
来捕捉:
// try {
let p = new Promise((resolve, reject) => {
throw new Error("I'm error");
// reject(new Error("I'm Error"));
});
// }catch(e) {
// console.log('catch',e);
// }
p.catch(result => {
console.log(result);
});
这样就捕捉到错误。所以:
Async-Await
async
和await
在干什么,async
用于申明一个function
是异步的,而await
可以认为是async wait
的简写,等待一个异步方法执行完成。
在Chrome
里申明这样一个函数,可以在控制台看到返回的其实就是一个Promise
对象。
扩展需要了解的就是Chrome
现在也支持asyncFunction
,可以在Chrome
控制台测试:
console.log(async function(){
}.constructor);
ƒ AsyncFunction() {
[native code] }
eg:
async function demo() {
let result = await Promise.resolve(123);
console.log(result);
}
demo();
Promise
虽然一方面解决了callback
的回调地狱,但是相对的把回调“纵向发展”了,形成了一个回调链。eg:
function sleep(wait) {
return new Promise((res,rej) => {
setTimeout(() => {
res(wait);
},wait);
});
}
/*
let p1 = sleep(100);
let p2 = sleep(200);
let p =*/
sleep(100).then(result => {
return sleep(result + 100);
}).then(result02 => {
return sleep(result02 + 100);
}).then(result03 => {
console.log(result03);
})
控制台:
300
后面的结果都是依赖前面的结果。
改成async/await
写法就是:
async function demo() {
let result01 = await sleep(100);
//上一个await执行之后才会执行下一句
let result02 = await sleep(result01 + 100);
let result03 = await sleep(result02 + 100);
// console.log(result03);
return result03;
}
demo().then(result => {
console.log(result);
});
因为async
返回的也是promise
对象,所以用then
接受就行了。
结果:
300
需要注意的就是await
是强制把异步变成了同步,这一句代码执行完,才会执行下一句。
如果是reject
状态,可以用try-catch
捕捉
eg:
let p = new Promise((resolve,reject) => {
setTimeout(() => {
reject('error');
},1000);
});
async function demo(params) {
try {
let result = await p;
}catch(e) {
console.log(e);
}
}
demo();
结果:
error
这是基本的错误处理,但是当内部出现一些错误时,和上面Promise
有点类似,demo()
函数不会报错,还是需要catch
回调捕捉。这就是内部的错误被“静默”处理了。
let p = new Promise((resolve,reject) => {
setTimeout(() => {
reject('error');
},1000);
});
async function demo(params) {
// try {
let result = name;
// }catch(e) {
// console.log(e);
// }
}
demo().catch((err) => {
console.log(err);
})
比如上面的例子:
如果这三个是你想异步发出的AJAX
请求,在这段代码里其实是同步的,第一个发出去才会发第二个,所以async/await
需要谨慎使用。
现在有一些forEach
或者map
的循环里,比如在forEach
里使用await
,这时候的上下文就变成了array
,而不是async function
,就会报错。这时候你就要想到是什么错误。