promise
首先,promise
是一种更优的异步编程解决方案,如果我们直接使用传统的回调方式去解决异步流程,就会避免不了大量的回调函数嵌套,形成回调地狱
,
ajax.get(url,function(data1){
ajax.get(url,data1,function(data2){
ajax.get(url,data2,function(data3){
ajax.get(url,data3,function(data4){
//...形成回调地狱
})
})
})
})
为了解决回调地狱的问题,commonjs社区率先提出了promise规范,在ESMA2015中被标准化成为了语言规范。
promise就是一个对象,用来表示一个异步任务,结束以后是成功还是失败。
promise一共有三个状态,pending(待定状态)
,fulfilled(成功状态)
,rejected(失败状态)
。
状态只能有pending到fulfilled,或者pending到rejected,且状态是不可逆的。
promise中有一个then方法,用来接收回调后的结果,then方法中有两个参数,第一个参数是成功
的回调,第二个参数是失败
的回调。
基本用法:
const promise = new Promise((resolve,reject)=>{
//这里用于兑现承诺
resolve("成功拉!!") // 兑现成功
//reject(new Error("失败拉!!")) // 兑现失败
})
promise.then((value)=>{
console.log(value) //输出的成功的值
},error=>{
//console.log(error) //输出的失败的值
})
promise配合ajax使用案列:
//封装ajax
function ajax(url){
return new Promise(function(resolve,reject){
var xhr = new XMLHttpRequest()
xhr.open('GET',url)
xhr.responseType ='json'
xhr.onload=function(){
if(this.status===200){
//代表成功
resolve(this.response)
}else{
reject(new Error(this.statusText))
}
}
xhr.send()
})
}
//使用
ajax('/api/test.json')
.then(data=>{
console.log(data) //请求成功的结果
},reason=>{
console.log(reason) //请求失败的原因
})
promise的链式调用
用来解决回调地狱的问题,是我们的代码更加的扁平化。
上面的代码可以这样使用:
//使用
ajax('/api/test.json')
.then(data=>{
console.log(data)//请求成功的结果
//promise 对象的then方法会返回一个全新的peomise对象
return ajax('/api/test2.json') //返回第二个url请求的结果
},reason=>{
console.log(reason) //第一个url错误的捕获
})
//后面的then方法就是为上一个then返回的promise注册回调
.then((test2)=>{ //前面的then方法的返回值会作为后面then方法的回调的参数
console.log(test2) //输出的为第二个url返回的结果
return ajax('/api/test3.json') //返回第三个url请求的结果
})
.then((test2)=>{
console.log(test2) //输出的为第三个url返回的结果
})
//....
Promise的异常处理
- 我们可以一层一层的捕获:
ajax('/api/test.json')
.then(data=>{
console.log(data)
return ajax('/api/test2.json')
},reason1=>{
console.log(reason1)//捕获url1的请求错误
})
.then((test2)=>{
console.log(test2)
return ajax('/api/test3.json')
},reason2=>{
console.log(reason2)//捕获url2的请求错误
})
.then((test2)=>{
console.log(test2)
},reason3=>{
console.log(reason3)//捕获url3的请求错误
})
- 可以使用promise提供的catch对我们的请求进行捕获
ajax('/api/test.json')
.then(data=>{
console.log(data)
return ajax('/api/test2.json')
})
.catch((reason)=>{
console.log(reason)
})
实际上 catch 方法就相当于我们的then方法的第一个值传入了undefined
ajax('/api/test.json')
.then(data=>{
console.log(data)
return ajax('/api/test2.json')
})
.then((undefined,reason)=>{
console.log(reason)
})
catch这种方式更适用于链式调用
,它可以捕获到每次then回调的错误结果,我们可以这样用:
ajax('/api/test.json')
.then(data=>{
console.log(data)
return ajax('/api/test1.json')
})
.then(data=>{
console.log(data)
return ajax('/api/test2.json')
})
.catch((reason)=>{
console.log(reason) //1和2有一个发生错误都会捕获到
})
Promise中的静态方法
1.resolve() 快速创建一个成功的对象
Promise.resolve('33')
.then((value)=>{
console.log(value)
})
这种写法等同于:
new Promise((resolve,reject)=>{
resolve("成功拉!!")
})
- reject() 快速创建一个失败的promise对象
Promise.reject(new Error('失败!!!'))
.then((value)=>{
console.log(value)
})
Promise.all()
promise并行执行的方法Promise.all()
这个方法可以将多个promise
合并为一个promise
统一进行管理
Promise.all()
方法接收的是一个数组
,数组中的每一个元素是一个promise对象
,我们可以把这些promise对象看作是一个个的promise任务
,Promise.all()
方法会返回一个全新的promise对象
当所有的promise
都完成过后,我们返回的全新的promise才会完成,成功的返回的是一个数组
,包含了每一个promise对象成功返回的结果
如果有一个promise失败
了,这个promise.all()就会以失败
结束
var promise = new Promise.all([
ajax('/api/test1.json'),
ajax('/api/test2.json'),
ajax('/api/test3.json')
])
promise.then(value=>{
//所有的promise都完成过后,才会打印value
//value为一个数组
})
.catch(err=>{
console.log(err) //有一个失败就会被捕获到错误信息
})
Promise.race()
Promise.race()也是把多个promise组合到一起的方法
与promise.all()的相同点:
都是传递一个数组
不同点:
promise.all()等待所有任务结束才会结束,Promise.race()只会等待第一个结束的任务,就是说Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
},1000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('failed')
}, 500)
})
Promise.race([p1, p2]).then((result) => {
console.log(result) //
}).catch((error) => {
console.log(error) // 打印的是 'failed'
})
Generator
generator(生成器)是ES6标准引入的新的数据类型,它是一种更优的异步编程解决方案。
基本用法:跟普通函数声明时的区别是加了一个*号
function *foo(){
console.log("generator")
}
foo()
上面的代码并不会执行,我们只有调用foo()函数的next()方法才会执行foo函数
function *foo(){
console.log("generator")
}
foo().next() // generator
通过yield语句可以在生成器函数内部暂停代码的执行使其挂起,此时生成器函数仍然是运行并且是活跃的,其内部资源都会保留下来,只不过是处在暂停状态。
在迭代器上调用next()方法可以使代码从暂停的位置开始继续往下执行。
function *foo(){
const res = yield "keke"
console.log(res) //ff next方法传递过来的值
}
}
const generator = foo()
const result = generator.next() //result表示接收到的值
console.log(result)//{ value: 'keke', done: false }
generator.next("ff")
用generator进行异步操作处理:
function ajax(url){
return new Promise(function(resolve,reject){
var xhr = new XMLHttpRequest()
xhr.open('GET',url)
xhr.responseType='json'
xhr.onload=function(){
if(this.status===200){
//代表成功
resolve(this.response)
}else{
reject(new Error(this.statusText))
}
}
xhr.send()
})
}
**使用 generator 处理异步:**
function *main(){
//使用try catch捕获异常
try{
const url = yield ajax('/api/test.json')
console.log(url) //拿到返回值
}catch(err){
console.log(err)
}
}
const generator = main()
const result = generator.next()
//result.value是一个promise对象,我们可以调用then方法获取data
result.value.then((data)=>{
generator.next(data)
},reason=>{
generator.throw(new Error(reason)) //捕获到错误扔出
})
处理多个异步
function* main() {
try {
const url = yield ajax('/api/test.json')
console.log(url) //拿到url返回值
const url2 = yield ajax('/api/test2.json')
console.log(url2) //拿到url2返回值
const url3 = yield ajax('/api/test3.json')
console.log(url3) //拿到url3返回值
} catch (err) {
console.log(err)
}
}
const generator = main()
const result = generator.next()
result.value.then((data) => {
const result2 = generator.next(data)
if (result2.done) return
result2.value.then((data) => {
const result3 = generator.next(data)
if (result3.done) return
result3.value.then((data) => {
generator.next(data)
})
})
}, reason => {
generator.throw(new Error(reason))
})
上面的代码我们可以写到一个递归函数里面,结束条件是当 reault.done为true的时候结束,对代码进行优化:
const generator = main()
const result = generator.next()
//封装到getGenerators函数里面,
function getGenerators(result){
if(!result.done){
result.value.then(data=>{
getGenerators(generator.next(data))
},err=>{
generator.throw(new Error(reason))
})
}
}
//调用
getGenerators(result)
async/await
是es2017新增的一个异步处理方案,它是一个语法糖,用起来很简单
用法如下:
//在函数前面加async
async function main() {
try {
//await代表等待
const url = await ajax('/api/test.json')
console.log(url) //拿到url返回值
const url2 = await ajax('/api/test2.json')
console.log(url2) //拿到url2返回值
const url3 = await ajax('/api/test3.json')
console.log(url3) //拿到url3返回值
} catch (err) {
console.log(err)
}
}
main()
``