文章书写原则
- 最小知识原则
本文章中的函数用es5函数的形式,不涉及箭头函数
基本使用
var promise = new Promise(function(resolve,reject){
//用setTimeout延时1s模拟异步调用,比如网络请求
setTimeout(function(){
//用一个随机数 0或1 表示网络请求的成功或失败
var status = Math.round(Math.random())
if(status){//status===1 请求成功
var data = '请求成功咯' //网络请求拿到的数据
resolve(data);
}else{ //status === 0 请求失败
var err = '请求失败咯' // 错误信息
reject(err);
}
},1000)
})
promise.then(
function(res){ //成功的回调
console.log('成功的回调被调用')
console.log(res)
},
function(err){ // 失败的回调
console.log('失败的回调被调用')
console.log(err)
}
)
new Promise()返回一个promise实例,Promise构造函数接收一个函数作为参数,这个函数也接收两个回调函数作为参数,分别是
- resolve()
异步请求成功时调用,参数是要返回的数据 - reject()
异步请求错误时调用,参数是要返回的数据
promise实例有一个then()方法,方法也接收两个回调函数作为参数,分别是
- 成功的回调,如示例例代码中写的。函数的参数是resolve()传递的数据
function(res){
console.log('成功的回调调用')
console.log(res)
},
- 失败的回调,如示例例代码中写的。函数的参数是reject()传递的数据
function(err){
console.log('失败的回调被调用')
console.log(err)
}
可以理解new Promise(func)
中func函数
的两个参数函数就是promise.then(func1,func2)
中then函数
的两个回调函数
案例:微信小程序api实现Promise化
微信小程序原生的网络请求api
wx.request({
url: 'test.php', //仅为示例,并非真实的接口地址
data: {
x: '',
y: ''
},
header: {
'content-type': 'application/json' // 默认值
},
success (res) {
console.log(res.data)
}
})
实现promise化的网络请求api
//promise化的方法
function promisify(func){
return function(obj){
return new Promise(function(resolve,reject){
//根据微信api指定的参数
func({
...obj,
success: resolve,
fail: reject
})
})
}
}
const requst = promisify(wx.request)
//调用promise化的网络请求api
const result = request({
url: 'test.php', //仅为示例,并非真实的接口地址
data: {
x: '',
y: ''
},
header: {
'content-type': 'application/json' // 默认值
}
})
//可以用promise的链式调用了,可以一直then下去,最后可以catch捕获一下可能发生的网络请求失败(相当于promise状态变为rejected)
result.then(function(res){
console.log('请求成功了,响应的内容:',res)
}).catch(err){
console.log('请求发生错误了,错误:',err)
}
Promose的定义
MDN中的描述:
Promise 对象是一个代理对象(代理一个值),被代理的值在Promise对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的promise对象
如上的request
的promise化,实际上是代理了它的请求状态,这时request的请求状态是未知的,可能请求失败也可能请求成功。
所以我为request的成功和失败状态分别绑定了resolve函数和reject函数
// ......
func({
...obj,
success: resolve,
fail: reject
})
// ......
MDN的描述中所指的处理方法handlers
就是function(resolve,reject){}
// ......
return new Promise(function(resolve,reject){
func({
...obj,
success: resolve,
fail: reject
})
})
// ......
经过promise化的api就可以像同步代码那样有返回值,如下返回了一个promise对象result
const result = request({
url: 'test.php', //仅为示例,并非真实的接口地址
data: {
x: '',
y: ''
},
header: {
'content-type': 'application/json' // 默认值
}
})
这个promise对象它以自己状态代表着未来出现的结果(成功或失败)。
Promise的状态
Promise有三种状态,分别是
- pending
也就是promise的初始化状态,代表着未来出现的结果还未确定 - fulfilled
出现的结果确定,代表操作成功 - rejected
出现的结果确定,代表操作失败
promise的状态改变是一个不可逆的过程,只能从panding--> fulfilled/rejected
,而不能逆过来。
- panding --> fulfilled
Promise.resolve()方法被调用时,状态从panding变为fulfilled - panding --> rejected
Promise.reject()方法被调用时,状态从panding变为rejected
如在小程序api中,当请求成功时调用handers中的resolve方法;失败时调用reject方法
// ......
func({
...obj,
success: resolve,
fail: reject
})
// ......
也可以用Promise的静态函数直接得到一个状态已经确定的promise实例。如下
let obj = '可以是任意对象'
let p = Promise.resolve(obj)
console.log(promise)
变量p是一个状态为fulfilled的Promise实例(fulfilled 等同于 resolved
)
同理:
Promise的API和实例方法
- Promise.all(iterable)
- Promise.race(iterable)
- Promise.reject(reason)
返回一个状态为rejected的promise实例,且实例的值为reason - Promise.resolve(value)
返回一个状态为fulfilled的promise实例,且实例的值为value - p.then(onFulfilled, onRejected)
接收两个回调参数,成功状态的回调和失败状态的回调。失败状态的回调常常省略不写,而用p.catch方法代替 - p.catch(onRejected)
接收一个回调参数,状态为rejected时调用。等价于p.then(undefined, onRejected)