前言
Promise,用于解决回调地域带来的问题,将异步操作以同步的操作编程表达出来,避免了层层嵌套的回调函数。
什么是 Promise
所谓的 promise,简单的来说就是一个容器,里面保存着某个未来才会结束的事件(也就是我们的异步操作)的结果。从语法上面来说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
Promise特性
- promise 对象代表一个异步操作,有三种状态:pending、fulfilled、reject
- 任何其他状态都无法改变这个状态。这也是 Promise 这个名字的由来。'承诺'表示其他手段无法改变它的状态。
Promise 的出现解决什么问题
promise其实就是一个异步编程方案,在 promise 出现之前总会遇到所谓的'回掉地域'的嵌套代码
step(1, function() {
step(2, function() {
step(3, function() {
……….
})
})
})
都知道这种"回调地狱",是一种很让人恼火的代码书写格式,嵌套多层之后会让人阅读起来怀疑人生的。但是这种"回调地狱"真的就只有格式的问题嘛?显然不是。
引用例子
一个来自《YDKJS》的例子:一个程序员开发了一个付款的系统,它良好的运行了很长时间。突然有一天,一个客户在付款的时候信用卡被连续刷了五次。这名程序员在调查了以后发现,一个第三方的工具库因为某些原因把付款回调执行了五次。在与第三方团队沟通之后问题得到了解决。
上面的例子就是一个 信任问题 回调函数的方式会引发很多信任问题,例如重复调用,调用太晚等等问题。那么promise怎么解决上述两个问题的呢?
Promise意义
- 可读性
首先是 Promise 的 then 方法,支持我们在回调写在 then 方法中,让我们在日常开发中可以很清楚的看到,比如上面的代码就可以改写成
Promise.resolve(1).
.then(step => ++setp)
.then(step => ++setp)
.then(step => ++setp)
...
- Promise 承诺的严谨性
它与普通的回调方式的区别在于
普通方式,回调成功之后的操作直接写在了回调函数里面,而这些操作的调用是由第三方控制
Promise方式 回调只负责成功之后的通知,而回调成功之后的操作放在 then 的回调函数里面,由 Promise 精确控制。
注意 Promise 的状态不可逆。一旦发生改变就没有办法改变成任何一种状态。Promise 只能是异步的,所以不会出现异步的同步调用。
Promise缺点
- 无法取消 Promise 一旦新建它就会立即执行,无法中途取消
- 如果不设置回调函数,Promise 内部抛出的错误不会反应到外部。
- 当处于 pending 状态,无法得知目前进行到哪一阶段(刚开始还是快结束)
如何使用Promise
Promise 对象是一个构造函数,用来生成 Promise 实例
Promise 构造函数接收一个函数作为参数,该函数的两个参数分别是 resolve 和 reject,这两个参数也函数,由 JavaScript 提供,不需要自己添加
Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。但一般不建议给then加两个参数,建议使用.then完成resolved状态的操作,使用.catch完成rejected的操作。
像这样:
const promise = new Promise( (resolve,reject) => {
resolve('ok');
reject('error')
})
promise.then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
还可以用promise实现ajax的操作:
const getJSON = function(url){
const promise = new Promise((resolve,reject) => {
const handler = function(){
if(this.readyState !== 4){//这两个if语句主要用来判断请求是否成功
return;
};
if(this.status === 200){
resolve(this.response)//这是成功请求后,将返回的数据传到回调函数中
}else{
reject(new Error(this.statusText))//这是失败后,将原因返给catch
}
};
const xmlHttp = new XMLHttpRequest();//声明一个XMLHttpRequest对象的实例
xmlHttp.open("get", url);//设置要发送的方法和地址
xmlHttp.onreadystatechange = handler;//在这里调用上面定义的handler
xmlHttp.responseType = "json";
xmlHttp.setRequestHeader("Accept", "application/json");//设置请求头,规定接受json类型的数据
xmlHttp.send();//真正的发送请求
});
return promise;
};
getJSON("url").then( res => {
//成功后的操作
}).catch(err => {
//失败后的提示
})
Promise可以嵌套使用,就是将一个Promise实例作为另一个Promise实例的resolve方法的参数传入。
说说then方法,这个方法是定义在Promise的原型上的,then方法返回的是一个新的Promise实例,因此可以采用链式写法,即then方法后面调用另一个then方法。
再来说几个Promise常用的api吧!
Promise.prototype.finally():
Finally方法用于不管promise对象的最后状态如何,都会执行的操作
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
Promise.resolve():
- 这个方法用来将参数转变成Promise对象
- 参数是一个Promise实例:不改动
- 参数是一个thenable对象:会将这个对象转为 Promise 对象,然后就立即执行thenable对象的then方法。
- 参数不是具有then方法的对象,或根本就不是对象:返回一个新的Promise对象,状态为resolved
- 不带有任何参数:直接返回一个ersolved状态的Promise对象
Promise.reject()
Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected
Promise.all():
const p = Promise.all([p1, p2, p3]);
用于将多个Promise实例,包装成一个新的Promise实例。这个方法接收一个数组作为参数,且都是Promise实例,如果不是,就会先调用Promise.resolve方法。
注意:
只有当数组中的实例的状态都是fulfilled,p才会变成fulfilled,此时,p1,p2,p3的返回值组成一个数组,传递给p的回调函数。
只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
Promise.race():
和all方法类似,也是讲多个Promise实例包装成一个。
但不一样的是,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
在实际开发中,我们总希望让同步函数同步执行,异步函数异步执行,但如果同步函数想用Promise来做处理,能否实现同步呢?答案是肯定的。
这就要说到Promise.try()方法了
const f = () => console.log('now');
Promise.try(f);
console.log('next');
// now// next
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。