Promise
- 主要用于异步计算
- 可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果。
- 可以在对象之间传递和操作Promise,帮助我们更好地处理队列。
历史背景
- JavaScript为检查表单而生。
- 创造他的首要目标是操作DOM
- 所以,JavaScript的操作大多是异步的,避免界面冻结,完成顺序和交付顺序无关。
1.异步操作的常见语法
-
事件侦听与响应
-
回调
先调用一个外部函数,传递给他一个回调函数
2.浏览器中的JavaScript
-
异步操作以事件为主
-
回调主要出现在Ajax 和File API
有了node.js(无阻塞,高并发,异步操作是其保障,大量操作依赖回调函数,稍有不慎,就会踏入回调地狱,不好维护)之后,对异步的依赖进一步加剧异步处理回调的时候,不能正常地使用try catch throw error的处理机制,因为不在一个栈中,需要return callback
- 异步回调函数会在一个新的栈里执行,在这个栈里面,没办法获取之前栈的信息的,之前的栈,也没有办法捕获这个栈抛出的异常,所以不能使用try catch
- 外层作用域声明变量,交给内层作用域来使用,存在被修改的可能性
3.回调有四个问题
- 嵌套层次很深,难以维护
- 无法正常使用return 和throw
- 无法正常的检索堆栈信息(每一次回调,都是在系统层面上的新的堆栈)
- 多个回调之间,难以建立联系(一个回调一旦开始启动,就没有办法对他进行操作)
4.promise
- promise
new Promise(
//执行器 executor
function(resolve,reject){
//一段耗时很长的异步操作
resolve();//数据处理完成
reject();//数据处理出错
}
)
.then(function A (){
//成功,下一步
},function B(){
//失败,做相应处理
})
- Promise是一个代理对象,他和原先要进行的操作并无关系
- 它通过引入一个回调(把其他的回调展开,全部变成基于promise的回调),避免更多回调
- Promise有三个状态
- pending[待定]初始状态
- fulfilled[实现]操作成功
- rejected[被否决]操作失败
当promise状态发生改变时,就会触发.then()里的响应函数处理后续步骤
promise的状态一经改变,不会再变
promise实例一经创建,执行器立即执行
- .then()
- .then()接受两个函数作为参数,分别代表fulfilled和rejected
- .then()返回一个新的Promise实例,所以它可以链式调用
- 当前面的Promise状态改变时,.then()根据其最终状态,选择特定的状态响应函数执行
- 状态响应函数可以返回新的Promise,或者其他值
- 如果返回新的Promise,那么下一级.then()会在新Promise状态改变之后执行
- 如果返回其他任何值,则会立即执行下一级.then()
.then()里有.then()的情况
因为.then()返回的还是promise实例。会等里面的.then(执行完,再执行外面的。对于我们来说,此时最好将其展开,会更好读。)



we-have-a-problem-with-promises
-
promises 的奇妙在于给予我们以前的
return与throw每一个 promise 都会提供给你一个
then()函数 (或是catch(),实际上只是then(null, ...)的语法糖)。当我们在
then()函数内部时:我们可以做什么呢?有三种事情:
-
return另一个 promise (“composing promises”) -
return一个同步的值 (或者undefined) -
throw一个同步异常
-
-
错误处理
-
reject ("错误信息").then(null,message=>{})
-
throw new Error('错误信息').catch(message=>{})
推荐使用第二种,更加清晰好读,并且可以捕获前面的错误
在catch里面处理错误时,仍然会返回promise实例,也有两个状态
强烈建议在所有队列最后都加上.catch(),以避免漏掉错误处理造成意想不到的问题
-
6.Promise.all()
-
Promise.all([p1,p2,p3,...]) 用于将多个Promise实例,包装成一个新的Promise实例。
-
返回的的实例就是普通的Promise
-
接受一个数组作为参数
-
数组里可以是Promise对象,也可以是别的值,只有Promise会等待状态改变
-
当所有子Promise都完成,该Promise完成,返回值是全部值的数组
-
有任何一个失败,该Promise失败,返回值是第一个失败的子Promise的结果
-
Promise.all()最常见的就是和.map()连用
-
实现队列
-
使用.forEach()
function queue(things){ let promise = Promise.resolve(); things.forEach(thing =>{ promise = promise.then( ()=>{ return new Promise( resolve => { doThing(thing, ()=>{ resolve(); }); } ); } ); }); return promise; } queue(['lots','of','things',...])- 常见错误:没有把.then()产生新Promise实例赋给promise,没有生成队列
-
使用.reduce()
function queue(things){ return things.reduce( (promise,thing) =>{ return promise.then( ()=>{ return new Promise( resolve =>{ doThing(thing,()=>{ resolve(); }); }); } ); },Promise.resolve() ); } queue(['lots','of','things',...])- Promise实例创建之后,会立刻运行执行器代码,所以这个也无法达成队列的效果。
7.Promise.resolve()
返回一个fulfilled的Promise实例,或原始Promise实例。
-
参数为空,返回一个状态为fulfilled的Promise实例
-
参数是一个跟Promise无关的值,同上,不过fulfilled响应函数会得到这个参数
-
参数为Promise实例,则返回该实例,不做任何修改
-
参数为thenable,立即执行他的.then()
对象里面有个then(){}
8.Promise.reject()
- 返回一个rejected的Promise()实例
- Promise.reject()不认thenable
9.Promise.race()
类似Promise.all(),区别在于它有任意一个完成就算完成。
- 把异步操作和定时器放在一起
- 如果定时器先触发,就认为超时,告知用户
10.promise常用做法
- 把回调包装成Promise(可读性更好,返回的结果可以加入任何Promise队列)
- 把任何异步操作包装成Promise
-