Promise已经作为JS的ES6标准,已经正式进入了浏览器环境和Node.js环境,但是对于程序员的需求来说,现在的Promise的功能还是有点不足的,比如说,我要设定一组Timeout该怎么做呢?
传统的同步方法实现起来很简单
let count = 10;
const func = () => {
if(count > 0) {
setTimeout(func, 1000);
count -= 1;
}
}
复制代码
这样我们就能实现10次,每次1秒的定时设定了,是不是很简单。
但是现在的问题是要用异步的方式来实现,那么继续使用原来的方法看看把
let count = 10;
const func = async () => {
if(count > 0) {
setTimeout(func, 1000);
count -= 1;
}
}
复制代码
唔...看起来似乎也没有问题,真的没有问题吗?请仔细的想想看func
的类型,在同步方法中func
的类型是Function
,但是在异步方法中也是Function
吗?NO!并不是,在异步方法中func
的类型是Promise
!OK,那么问题来了,既然func
的类型是Promise
那么你怎么可能用setTimeout(function, timeout)
这个函数呢?你传递的类型都不多,结果自然是无法执行了!
那么有什么方法可以是实现异步的定时调用呢?毕竟有时候我们会需要一些网络传输的测试,当网络状况不良的时候,希望通过定时测试网络连接,获取网络状况,这里就要用到Promise.race()
这个方法了,你或许说会文为什么不用bluebird
库,里面也有实现的方法,这里我想提醒的是Promise.race()
这个方法是目前在浏览器端和Node.js端中都是原生提供的方法,实现起来的移植性更高,那么现在我们来假想一个使用场景,现在我们需要连接远端的服务器,但是并不能保证100%的成功率,因此需要去ping一下服务器看看服务器是不是还活着
const axios = require('axios');
// 最大的连接重试次数
const MAX_RETRYS = 10
let count = 0;
/**
* 测试服务器是不是还活着
* @method {Function} resolve Promise的成功调用方法
* @method {Function} reject Promise的失败调用方法
*/
const ping = async (resolve, reject) => {
const response = axios.get(...);
if(response.status === 200) {resolve();}
else if(count > MAX_RETRYS) {reject();}
count += 1;
}
// 以下是异步定时调用方法
// 每隔1秒重新ping一次
const tasks = [...Array(MAX_RETRYS + 1).keys()].map(i => {
return new Promise((resolve,reject) => {
setTimeout(ping(resolve, reject), i * 1000)
})
})
// 处理ping通的
tasks.race().then(() => {.../*成功的后续执行*/})
.catch(() => {.../*失败的后续执行*/})
复制代码
这里我使用的方法是通过产生一组任务来模拟时间间隔,可以这么理解,我在时刻0的时候去ping一下,时刻1秒的时候去ping一下,时刻2秒的时候去ping一下,以此类推产生一组ping的任务,当时刻到的时候才去执行,效果跟同步的方法差不多,但是有一个与同步方法特别的不同的地方,就是这个任务队列不能是无穷大的,因此要设定一个最大尝试次数,其实实际应用时我们也会设置这么一个限制值,总不可能用户等一个小时连接服务器吧
对了这里解释下[...Array(MAX_RETRYS+1).keys()]
的代码含义,这个方法类似于python
中的range()
函数,但是Javascript没有原生的实现方法,因此这里使用了ES6的新特性,简单的模拟了range()
函数,具体含义大家看官方文档吧,很简单的
希望我的这个方法对你有帮助