promise async await generators之间的关系和区别
async/await的主要益处就是有效的避免的回调地狱
- async表示这是一个async函数,await只能用在这个函数里。async也是一个promise对象
- await表示在这里等待promise返回结果了,再继续执行
- await后面跟着的应该是一个promise对象
Promise的含义
Promise是异步编程的一种解决方案。ES6原生提供了Promise对象
简单来说Promise是一个对象,里面保存着某个未来才会结束的事件的结果
Promise的特点
Promise有两个特点:
1,对象的状态不受外界的影响。Promise对象代表一个异步操作,存在三种状态pending(进行中),fulfilled(已成功)和reject(已失败)。只有异步操作的结果可以决定当前是那种状态,其他操作都无法改变状态。
2,一旦状态发生变化,便不会再次改变,任何时候都可以得到这个结果。Promise状态的变化无非是两种pending到fulfilled或pending到reject,一旦这两种情况发生,状态就会凝固,不会发生变化称为resolved(已定型)。如果改变发生,在对Promise对象添加回调函数,也会立即得到这个结果
Promise的劣势
1,无法取消Promise,一旦新建他就会立即执行,无法中途取消,2,如果不设置回调,Promise内部将会抛出错误,而且不会反映到外部
3,当处于pending状态,无法得知目前进展到哪一个阶段
用法
ES6规定,Promise对象是一个构造函数。用来生成Promise实例
let Promise=new Promise(function(resolve,reject){
if(/*异步操作成功*/){
resolve(value)
}else{
reject(error)
}
})
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject,他们是两个函数,有js的引擎提供,不用自己部署。
resolve函数的作用是:将Promise对象的状态从“未完成”变成“成功”(从pending变成resolved),在异步操作成功的时候调用,并将异步操作的结果,作为参数传递出去
reject函数的作用是:将Promise对象的状态从“未完成”变成“失败”(从pending变成rejected),在异步操作失败的时候调用,并将异步操作的报的错,作为参数传递出去
Promise的实例生成以后,可以用then方法分别制定resolved状态和rejected状态的回调函数
promise.then(function(value) {//异步的
// success
}, function(error) {
// failure
});
then方法可以接受两个回调函数作为参数,第一个回调函数是Promise
对象的状态变为resolved
时调用,第二个回调函数是Promise
对象的状态变为rejected
时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise
对象传出的值作为参数。
then
方法返回的是一个新的Promise
实例(注意,不是原来那个Promise
实例)。因此可以采用链式写法,即then
方法后面再调用另一个then
方法。
案例库
let Promise=new Promise((resolve,reject)=>{
console.log("Promise");
resolve();
})
Promise.then(function(){
console.log("resolve");
})
console.log("HI")
依次输出 Promise--->HI--->resolve
实例的Promise会立即执行,所以首先输出Promise,then方法制定的回调函数,在当前所有脚本执行完之后再回执行,所以会先输出HI,最后输出resolve
用Promise
对象实现的 Ajax 操作
const getJSON = function(url) {
const promise = new Promise(function(resolve, reject){
const handler = function() {
if (this.readyState !== 4) {
return;
}
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
const client = new XMLHttpRequest();
client.open("GET", url);
client.onreadystatechange = handler;
client.responseType = "json";
client.setRequestHeader("Accept", "application/json");
client.send();
});
return promise;
};
getJSON("/posts.json").then(function(json) {
console.log('Contents: ' + json);
}, function(error) {
console.error('出错了', error);
});
上面代码中,getJSON是对 XMLHttpRequest 对象的封装,用于发出一个针对 JSON 数据的 HTTP 请求,并且返回一个Promise对象。需要注意的是,在getJSON内部,resolve函数和reject函数调用时,都带有参数。如果调用resolve函数和reject函数时带有参数,那么它们的参数会被传递给回调函数
简单的停顿执行
var sleep=function (time){
return new Promise(function(resolve,reject){
setTimeout(function(){
resolve();
},time)
})
}
var start=async function(){
console.log("start");
await sleep(3000);
console.log("end");
}
start()
先输出start,3秒后,在输出end
Promise的方法
Promise.prototype.then()
Promise.prototype.catch()
Promise.prototype.finally()
Promise.all()
Promise.race()
Promise.resolve()
Promise.reject()
这些方法可在阮一峰大神的日志中,找到详细的解释http://es6.ruanyifeng.com/#docs/promise#Promise-resolve
async和await
async-定义异步函数(async function someName(){…})
- 自动把函数转换为Promise
- 当调用异步函数时,函数的返回值会被resolve处理
- 异步函数内部可以使用await
await-暂停异步函数的执行(var result = await someAsyncCall())
- 当时用再Promise前面时,await等待Promise完成,并返回Promise
- await只能和Promise一起使用,不能喝callback一起使用
- await只能用在async函数中
案例
async function get(){
let a=await getA() //花费2s
let b=await getB() //花费3s
let c=await gebtC() //花费4s
return a*b*c
}
每当遇到await Promise都会停下直到运行结束 总共花费2+3+4秒,相当于把异步变成同步
async异步的简写,用于声明一个函数是异步的,
await可以认为是async wait 的简写,await用于等待一个异步方法的执行完成
await只能出现在async函数中
async有什么作用
async function test(){
return "hello"
}
let result=test();
console.log(result);
这种情况下会输出
Promise{"hello"}
async函数返回的是一个Promise对象,因为如果直接return一个直接量,async会把这个直接量通过Promise.resolve()封装成Promise对象
当async返回的是一个Promise对象,所以最外层不能用await获取其返回值的情况下,使用原来的方式then
test().then((e)=>{
console.log(e)
})
经典面试题
async function sleep(time){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve();
},time)
});
}
(async function(){
console.log(new Date());
await sleep(3000);
console.log(new Date());
})() //(fn)()代表自调用函数
先输出Mon Feb 23 2017 21:52:11 GMT+0800 (CST);
在输出Mon Feb 23 2017 21:52:14 GMT+0800 (CST);
Generators
也是ES6里的一个新特性,能够 暂停/执行代码,yield表示暂停,iterator.next表示执行下一步
await/async与Promise结合使用
//封装一个ajax,返回一个Promise
function requestP(url){
return new Promise((resolve,reject)=>{
ajax(url,(reponse)=>{
resolve(JSON.parse(response))
})
})
}
(async ()=>{
//获取产品参数
let data=await requestP("product.json");
//获取用户数据
let user=await requestP("user.json");
//获取评论数据
let product=await requestP("comments.json");
}())
案例
Promise的用法:reject reslove跟在then之后 的catch
一旦执行reject或者reslove,后面的promise状态不会改变
function test(){
//promise是一个构造函数,内部接收一个回调函数。
//回调函数内部有两个参数,reslove是执行成功的时候调用的,reject是失败调用的
var Promise=new Promise((reslove,reject)=>{
reslove(true)
})
return Promise;
}
//链式调用
test().then((value)=>{
//value会受到上一个reslove过来的值
return new Promise((reslove,reject)=>{
if(value){
reslove("success")
}else{
reject("fail")
}
})
}).catch((val)=>{
//捕捉异常
console.log(val)
}).then((value)=>{
//如果没有异常则继续上一次的值
})
async的返回总是一个promise对象,无论是否使用await
function wait(ms){
return new Promise((r)=>{
setTimeout(r,ms)
})
}
async function hello(){
await wait(500)
return "world"
}
//调用hello()返回 world来完成Promise
async function foo(){
await wait(1000);
throw Error("bae")
}
//调用到()会返回Error来拒绝promise