Promise
一、 Callback hell
1、回调地狱:多个异步任务顺序执行,形成的多层回调函数的嵌套结构,就称为回调地狱现象。
缺点:代码结构嵌套层次太深,导致没有可读性,难以维护。
二、Promise
基本概述
1、promise:专门解决回调地狱问题的一项新技术,保证了多个异步任务顺序执行
2、三个状态:
① pending : 在异步任务执行完之前,promise处于pending状态。
② fullfilled : 调用resolve( )时,整个promise对象变成fullfilled状态,就自动调用.then( )中
下一项任务
③ rejected : 当异步任务执行过程中出错,调用reject( )时,整个promise对象就变成rejected状态。
就不再调用.then( ),而是调用结尾的.catch( )
三、如何实现
(0). 所有异步函数不要加回调函数参数了!
(1). 用new Promise(function(resolve,reject){ ... })包裹住原来的异步函数代码。
强调: 原异步函数不需要做任何改变
(2). 在原异步函数最后执行的一句话之后,调用resolve()执行下一项任务!
结果: 自动执行.then()中串联的后续任务(下一个格子间,也可能是下一个函数)
(3). new Promise()是放在函数内创建的,所以,如果希望外部直到这里有一个格子间的对象可以串联,必须用return new Promise()将其返回到函数外部!
function 前一项异步函数(){
return new Promise(function(resolve,reject){
原异步函数内容
异步函数最后一句话之后: resolve()
})
}
(4). 调用return new Promise()所在的异步任务函数,既可以执行异步函数的任务,又可以返回格子间,可用.then()与下一项任务串联
前一项任务().then(下一项任务)
//下一项任务不要加(),因为不是立刻执行!
(5). 多一个异步任务串联: 任务1().then(任务2).then(任务3)
四、异步任务间如何传参
1、异步任务在调用resolve()时,是可以传参的 =>resolve(实参值)
2、在下一项任务的形参列表中定义形参变量接住上一个任务resolve()传过来的实参值
坑 使用resolve()传参时,传多个变量,只能接收一个变量
解决:用参数解构(展开语法),传多个值,可以放在数组或对象中传递:
resolve([“值1”,“值2”...])或 resolve ({属性1:值1, 属性2:值2,...})
function 下一项任务([形参1, 形参2]) 或 ({属性1, 属性2})
五、错误处理
(1). 其实: new Promise里有两个参数:
a. resolve,成功
b. reject, 错误处理, 执行 .catch()
c. 所以: new Promise(function( resolve, reject){ ... })
(2). 在异步任务中:
a. 如果正常执行,调用resolve(实参值),执行.then()
b. 如果出错,调用reject(错误消息),执行.catch()
(3). 接住错误消息:
.then(...).then(...).catch(function(errMsg){ ... })
六、Promise.all
1、多个异步任务同时执行,只有等最后一个异步任务执行完后在执行下面的操作
Promise.all([任务1,任务2,...]).then(后面的任务)
原理:异步任务,都是并发进行,只有当Promise.all执行完后,才会执行.then( )里的任务
2、Promise.all返回值, Promise.all([任务1,任务2,...]).then(function(arr){...})
返回值的顺序与异步函数执行结束的先后顺序无关,与Promise.all([...])中定义的异步函数顺序相同
而且arr的值是每一个异步函数中resolve(参数)的第一个参数值
七、 Promise.race
1、race
的使用:用于同时执行多个异步,如果那个先完,就直接结束,处理这个先完成的异步函数或者直接执行后面的操作
Promise.race([([任务1,任务2,...]).then(function(res){...})])
八、ES7 async
1、es7 对于Promise 在定义函数时没有简写
(async function( ){
await 任务1( )
await 任务2( )
...
任务n( )
})()//匿名函数自调