1、promise是什么:
- promise 对象用作异步计算
- 可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果
- 可以在对象之间传递和操作promise,帮助我们处理队列
2、为啥会有promise? 因为js有大量的异步操作
同步操作:
异步操作:
3、异步操作的常见语法:
- 事件侦听和响应
- 回调
4、为了解决回调地狱的问题,产生了promise
5、在异步回调的操作当中,无法使用try catch捕获异常,因为异步回调函数在新的栈里面运行,在新的栈里面无法获取之前栈的信息,之前的栈也无法捕获这个栈抛出的错误。
6、回调的四个问题
- 嵌套层次很深,难以维护
- 无法正常使用return和 throw
- 无法正常检索堆栈信息
- 多个回调之间难以建立联系
7、promise简介
Promise是一个代理对象,它和原先要进行的操作并无关系,我们只是把原先的操作放在了执行器里面
它通过引入一个回调,避免更多的回调
8、promise的三个状态
- pending【待定】初始状态
- fulfilled【实现】操作成功
- rejected【被否决】操作失败
当promise状态发生改变,就会触发.then()里的响应函数处理后续步骤,状态一经改变,就不会在变
9、简单的demo
eg1:
console.log("here we go");new Promise(resolve=>{setTimeout(()=>{resolve("hello");},2000)}).then(function(value){console.log(value+ " world")},function(err){console.log(err)})
输出结果:
hello world是两秒后输出来的
eg:2
console.log("here we go");new Promise(resolve=>{setTimeout(()=>{resolve("hello");},2000)}).then(value=>{console.log(value);return new Promise(resolve=>{setTimeout(()=>{resolve("world");},2000)})}).then(value=>{console.log(value +" world","---");})
输出结果:
eg:3
console.log("start");let promise = new Promise(resolve=>{setTimeout(()=>{console.log("the promise fulfilled");resolve("hello world");},2000);})setTimeout(()=>{promise.then(value=>{console.log(value)})},3000)
输出结果:
promise作为队列最为重要的一个特性:我们在任何一个地方,生成一个promise队列之后,可以把他作为一个变量传递到其他地方,如果我们的操作是很明显的队列状态,先进先出,我们可以在他的后面追叙任意多的then【下一步要执行的东西】,不管前面的状态是完成还是未完成,队列都会按照固定的顺序执行。如果未完成,会顺序完成;如果已完成,后面追加的then,也会得到前面promise返回的值。
eg:4
console.log("start");new Promise(resolve=>{setTimeout(()=>{resolve("hello");},2000);}).then(value=>{console.log(value);console.log("everyone");(function(){return new Promise(resolve=>{setTimeout(()=>{console.log("Mr.laurence");resolve("Merry Xmas");},2000);})}());return false;}).then(value=>{console.log(value + " world");})
在promise当中,如果不直接返回一个promise实例,它就会默认执行下一个环节,即使返回的是false,也会继续执行下一个环节。
10、 .then()
- .then() 接收两个函数作为参数,分别代表fulfilled 和 rejected
- .then() 返回一个新的Promise实例,所以它可以链式调用
- 当前面的Promise状态改变时,.then() 根据其最终状态,选择特定的状态响应函数执行
- 状态响应函数可以返回新的Promise,或者其他值
- 如果返回新的Promise,那么下一级 .then() 会在新Promise状态改变之后执行
- 如果返回其他值,则会立即执行下一级 .then()
11、 .then()里面有 .then() 的情况
因为 .then()返回的还是promise实例,会等里面的 .then()执行完毕,再执行外面的,对我们来说,此时,最好将其展开,把它们放在同一级,这样会更好读。
12、错误处理
Promise 会自动捕获内部异常,并交给rejected 响应函数处理。
console.log("start");new Promise(resolove=>{setTimeout(()=>{throw new Error("bye");},2000)}).then(value=>{console.log(value);},err=>{console.log(err,111)}).catch(error=>{console.log("Error:" + error)})
Promise中的错误处理有两种做法:
推荐使用第二种,更加清晰好读,并且可以捕获前面的错误
13、.catch()+.then()
强烈建议在所有队列最后都加上.catch() ,以避免漏掉错误处理造成意想不到的问题
catch()也会返回一个promise实例,并且如果其中没有抛出错误,它返回的promise实例也是 fulfilled状态,会继续执行后续的then
new Promise(resolve=>{setTimeout(()=>{resolve()},2000)}).then(value=>{console.log("start");throw new Error("test error");}).catch(error=>{console.log("i catch:" + error);// throw new Error("another error")}).then(()=>{console.log("arrive here");}).then(()=>{console.log("... and here");}).catch(err=>{console.log("no ,i catchc:",err)})
去掉 throw new Error("another error")的注释输出下面的结果:
14、Promise.all([p1,p2,p3,...]) 用于将多个promise实例,包装成一个新的promise实例,返回的实例就是普通promise
- 它接收一个数组作为参数
- 数组里可以是promise对象,也可以是别的值,只有promise会等待状态改变
- 当所有的子promise都完成,改promise完成,返回值是全部值的数组
- 有任何一个失败,该promise失败,返回值是第一个失败的子promise的结果
console.log("here we go");Promise.all([1,2,3]).then(all=>{console.log("1:",all);return Promise.all([function(){console.log("ooxx");},"xxoo",false]);}).then(all=>{console.log("2:",all);let p1 = new Promise(resolve=>{setTimeout(()=>{resolve("i/'m p1");},1500)});let p2 = new Promise(resolve=>{setTimeout(()=>{resolve("i/'m p2");},1450)});return Promise.all([p1,p2]);}).then(all=>{console.log("3:" ,all);let p1 = new Promise(resolve=>{setTimeout(()=>{resolve("i/'m p1");},1500)});let p2 = new Promise((resolve,reject)=>{setTimeout(()=>{reject("i/'m p2");},1000)});let p3 = new Promise((resolve,reject)=>{setTimeout(()=>{reject("i/'m p3");},3000)});return Promise.all([p1,p2,p3]);}).then(all=>{console.log(all,"all");}).catch(err=>{console.log("Catch:",err);})
15、Promise.all()与 .map() 结合使用
16、Promise实现队列
使用foreach实现
使用reduce实现