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使用案列:
//封装ajaxfunction 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方法的第一个值传入了undefinedajax(\'/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方法获取dataresult.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) returnresult2.value.then((data) => {const result3 = generator.next(data)if (result3.done) returnresult3.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新增的一个异步处理方案,它是一个语法糖,用起来很简单
用法如下:
//在函数前面加asyncasync 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()``