Promise是javascript中异步编程的一种解决方案,和传统的异步编程方案(回调、事件)相比,使用更加简洁,功能更加强大。ES6将其写进了语言标准,统一了语法。
一、Promise入门
1.1 创建
通常在创建Promise的时候,在外层进行一层封装,如下所示。
function runAsync(){
let p = new Promise((resolve,reject)=>{
if(/*异步操作成功*/){
resolve(value);
}else{
reject(error);
}
})
return p;
}
Promise的构造函数接收一个参数,是函数,并且传入两个参数:resolve,reject,分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数。
1.2 then函数
执行runAsync()
,并通过then
函数实现对异步结果的处理。
//情况1
runAsync()
.then(data=>{},error=>{})
//情况2
runAsync()
.then(data=>{})
then
函数接收两个参数或一个参数,参数的类型都是函数。
then
第一个参数中的data(函数的参数),是resolve(value)
中的value值。
同理,then第二个函数中的error,是reject(error)
中的error值。
1.3 链式操作的用法
Promise的精髓在于通过管理“状态”,使得回调方法及时调用,代码层次十分的清晰。
runAsync1()
.then(function(data){
console.log(data);
return runAsync2();
})
.then(function(data){
console.log(data);
return runAsync3();
})
.then(function(data){
console.log(data);
});
如上述代码,异步任务1执行成功后,再执行异步任务2,异步任务2成功后,再执行异步任务3。此应用场景下,如果使用回调进行嵌套,层级将十分复杂,不便于代码管理。但是使用Promise后,代码简洁明了。
runAsync()
返回的是Promise对象,通过then()
函数进行相应操作。如此情况,称作是“链式操作”。
1.4 catch函数
catch函数的作用:
指定reject的回调
捕捉then方法的异常,防止阻塞。
runAsync()
.then(data=>{})//可能出现异常错误
.catch(error=>{})
catch
函数接收一个参数(参数类型是函数),接收的函数传入一个参数值error,error可能是reject(error)回调函数的error值,即异步操作失败时的回调。
error参数的另一种情况:then函数中,传入的参数代码执行时,出现异常错误,catch将捕获该异常,达到不阻塞线程的目的。此时,error的参数即为该异常错误的string。
二、Promise进阶
2.1 all
Promise的all方法提供了并行多个执行异步操作的能力,并且在所有异步操作执行完后才执行回调。我们仍旧使用上面定义好的runAsync1、runAsync2、runAsync3这三个函数,看下面的例子:
Promise
.all([runAsync1(), runAsync2(), runAsync3()])
.then(function(results){
console.log(results);
});
其中results是所有resolve(data)
的data的数组。
2.2 race
all方法的效果实际上是「谁跑的慢,以谁为准执行回调」,那么相对的就有另一个方法「谁跑的快,以谁为准执行回调」,这就是race方法,这个词本来就是赛跑的意思。
Promise
.race([runAsync1(), runAsync2(), runAsync3()])
.then(function(result){
console.log(result);
});
可以使用race方法,实现fetch请求的请求超时。
三. Promise的高级使用
下面使用的demo代码是从react-native-fetch-blob截取的部分代码。
function fetchFile(options = {}, method, url, headers = {}, body):Promise {
...
let promise = null
...
let _progress, _uploadProgress, _stateChange
switch(method.toLowerCase()) {
...
default:
promise = fs.stat(url)
.then((stat) => {
total = stat.size
return fs.readStream(url,
headers.encoding || 'utf8',
Math.floor(headers.bufferSize) || 409600,
Math.floor(headers.interval) || 100
)
})
//*******关键代码1************//
.then((stream) => new Promise((resolve, reject) => {
stream.open()
info = {
state : "2",
headers : { 'source' : 'system-fs' },
status : 200,
respType : 'text',
rnfbEncode : headers.encoding || 'utf8'
}
_stateChange(info)
stream.onData((chunk) => {
//*******关键代码2************//
_progress && _progress(cursor, total, chunk)
if(headers.noCache)
return
cacheData += chunk
})
...
}))
break
}
//*******关键代码3************//
promise.progress = (fn) => {
_progress = fn
return promise
}
...
return promise
}
重点看关键代码1、2、3。
关键代码3:给promise添加progress属性,指定_progress回调方法。
关键代码2:指定_progress方法后,回到函数的执行。
关键代码1:创建promise对象。
给promise对象设置添加的属性:
let p = fetchFile(options,method,url,headers,body)
.progress((cursor, total, chunk)=>{})
p.then(res=>{})
.catch(error=>{})
扩展:通过delete删除对象属性,如
delete promise['progress']