以下是学习Promise时的一些笔记,仅供个人参考使用
1、Promise是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。ES6将其写进了语言标准,统一了用法,原生提供了Promise对象。有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。Promise也有一些缺点,比如一旦新建了它就会立即执行,无法中途取消。
2、基本用法:
ES6规定,Promise对象是一个构造函数,用来生成Promise实例。如下:
var promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由JavaScript引擎提供,不用自己部署。
resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从Pending变为Resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从Pending变为Rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
Promise实例生成以后,可以用then方法分别指定Resolved状态和Reject状态的回调函数。
promise.then(function(value) {
// success
}, function(value) {
// failure
});
then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为Resolved时调用,第二个回调函数是Promise对象的状态变为Reject时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。即then的value是resolve(value)和reject(error)传过来的。
then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,即Promise中所有函数执行完后才会执行then函数。
3、then()方法
Promise实例具有then()方法,也就是说,then()方法是定义在原型对象Promise.prototype上的。它的作用是为Promise实例添加状态改变时的回调函数。前面说过,then方法的第一个参数是Resolved状态的回调函数,第二个参数(可选)是Rejected状态的回调函数。就是说Promise状态变成Resolved或者Reject后就会去执行then方法。
then方法可以采用链式写法,
getJSON("/posts.json").then(function(json) {
return json.post;
}).then(function(post) {
// ...
});
上面的代码使用then方法,依次指定了两个回调函数。第一个then函数完成以后,会将返回结果作为参数,传入第二个then函数。采用链式的then,可以指定一组按照次序调用的回调函数。这时,前一个回调函数,有可能返回的还是一个Promise对象(即有异步操作),这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用。
getJSON("/post/1.json").then(function(post) {
return getJSON(post.commentURL);
}).then(function funcA(comments) {
console.log("Resolved: ", comments);
}, function funcB(err){
console.log("Rejected: ", err);
});
上面代码中,第一个then方法指定的回调函数,返回的是另一个Promise对象。这时,第二个then方法指定的回调函数,就会等待这个新的Promise对象状态发生变化。如果变为Resolved,就调用funcA,如果状态变为Rejected,就调用funcB。
如果采用箭头函数,上面的代码可以写得更简洁。
getJSON("/post/1.json").then(
post => getJSON(post.commentURL)
).then(
comments => console.log("Resolved: ", comments),
err => console.log("Rejected: ", err)
);
4、catch()方法:
Promise.prototype.catch()方法是.then(null,rejecton)的别名,用于指定发生错误时的回调函数,也就是then方法的第二个参数,第一个参数是Resolved方法。
5、所以,Promise的通常写法是
1)创建一个Promise
var promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
2)处理异步操作得出的结果:
// bad
promise
.then(function(data) {
// success
}, function(err) {
// error
});
// good
promise
.then(function(data) { //cb
// success
})
.catch(function(err) {
// error
});
解释:上面第一步是利用Promise的构造函数创建了一个Promise实例,创建后会马上执行,Promise里面包裹的是一个耗时的异步操作,resolve是操作成功绑定的回调函数,reject是操作失败绑定的回调函数。等所有的异步操作都执行完以后,如果是成功了就执行then方法,then方法中的参数data就是resolve(value)传过来的结果,如果操作失败就会执行catch函数,catch函数的参数就是 reject(error)传过来的结果,然后就可以在then和cath方法里面对上面的异步执行结果进行处理了。
二、使用Promise封装fetch的实例
1、定义一个post方法,返回一个Promise函数
static post = post(url,parame){
let requestUrl = baseUrl + url;
let body = JSON.stringify(parame);
let p1 = new Promise((resolve,reject)=>{
fetch(requestUrl,{
method:'POST',
///请求头参数
headers:{
'Accept': 'application/json',
'Content-Type': 'application/json',
},
/// 请求参数
body:body,
})
.then((response)=>response.json()) // 默认是返回的是json格式
.then((responseJson)=>{
// 拿到数据可以在此同意处理服务器返回的信息
resolve(responseJson);
})
.catch((error)=>{
let b = baseUrl;
reject(error);
})
});
let p2 = this.requestTimeout();
/// 因为fetch网络请求没有超时时间设置,所以使用Promise实现请求超时
return Promise.race([p1,p2]) //race是Promise的竞速函数,谁先执行完就返回谁
}
2、对请求返回的结果进行处理
post(Global.requestUrl.getVideoLibrary_url)
.then((responseData)=>{
// 对responseData进行处理
let data = responseData.data;
})
.catch(error=>{
// 对异常进行处理
this.setState({
error:true,
errorInfo:error,
})
})
详细:上面例子在react native中使用的全部代码
1、在HTTPUtil.js中
import Global from '../common/Global/Global'
const baseUrl = Global.config.baseUrl;
const timeoutSeconds = 20; // 网络超时
export default class HTTPUtil{
/// POST方法
static post(url,parame){
let requestUrl = baseUrl + url;
let body = JSON.stringify(parame);
let p1 = new Promise((resolve,reject)=>{
fetch(requestUrl,{
method:'POST',
///请求头参数
headers:{
'Accept': 'application/json',
'Content-Type': 'application/json',
},
/// 请求参数
body:body,
})
.then((response)=>response.json()) // 默认是返回的是json格式
.then((responseJson)=>{
// 拿到数据可以在此同意处理服务器返回的信息
resolve(responseJson);
})
.catch((error)=>{
let b = baseUrl;
reject(error);
})
});
let p2 = this.requestTimeout();
/// 因为fetch网络请求没有超时时间设置,所以使用Promise实现请求超时
return Promise.race([p1,p2])
}
/// Get方法
static get(url){
let requestUrl = baseUrl + url;
let p1= new Promise((resolve,rejcet)=>{
fetch(requestUrl)
.then((response)=>response.json())
.then((responseJson)=>{
// 拿到数据可以在此同意处理服务器返回的信息
resolve(responseJson);
})
.catch((error)=>{
reject(error);
})
});
let p2 = this.requestTimeout();
return Promise.race([p1,p2]);
}
/// 设置超时的方法
static requestTimeout(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
reject('链接超时');
},timeoutSeconds * 1000)
})
}
}
/*
使用:
import HTTPUtil from '../../http/HTTPUtil'
componentDidMount(){
HTTPUtil.get('https://facebook.github.io/react-native/movies.json')
.then((responseData)=>{
console.log(data);
})
.catch(error=>{
console.log(error);
})
HTTPUtil.post('https://mywebsite.com/endpoint/',{
firstParam: 'yourValue',
secondParam: 'yourOtherValue',
})
.then((responseData)=>{
console.log(data);
})
.catch(error=>{
console.log(error);
})
}
*/