promise用法都知道,再简单介绍一下:
Promise的构造函数接收一个参数,是函数,并且传入两个参数:resolve,reject,分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数。按照标准来讲,resolve是将Promise的状态置为fullfiled,reject是将Promise的状态置为rejected。
var p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log('执行完成');
if(true){ //某些判断条件,那就成功啦
resolve('成功后接收得数据');
} else {
reject('接收另外得参数')
}
}, 2000);
});
// then接收两个函数当参数哦,当然只用到成功得话,也可以只写成功那个
p.then((data)=>{
// resolve 成功执行,
},(data) => {
// reject 执行,
})
.catch(()=> {
// 如果程序报错了,就跑到这来喽,可以理解为错误捕获,估计也就是try catch那些玩意
})
Promise得精髓就是将我们从以往得回调地狱解脱了出来,虽然不是终极得解决办法,但链式操作已经大大大大大大得提高了。
它得一般打开方式就是定义一些要执行得函数,它大概长这样
function runAsync(){
var p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log('执行完成');
resolve('随便什么数据');
}, 2000);
});
return p;
}
然后链式得写法又长成了这样
runAsync1()
.then(function(data){
console.log(data);
return runAsync2();
})
.then(function(data){
console.log(data);
return runAsync3();
})
.then(function(data){
console.log(data);
});
下面我们开始重点~~~
Promise.all
promise.all接收个 Promise对象得数组,然后当这些promise都执行完了,它就又会执行个then下得函数,可以保证所有异步都加载完了,
Promise
.all([runAsync1(), runAsync2(), runAsync3()])
.then(function(results){
console.log(results);
});
标题是撕烂了,既然撕,那么我们就手动简单实现一遍 prmise.all(主要功能)
const isPromise = (obj) => {
if (!!obj && typeof obj === 'object' && typeof obj.then === 'function') {
return true
}
return false
}
const allPromiseDone = function (promiseArrs) {
const result = []
const lengthNum = promiseArrs.length
return new Promise((resolve, reject) => {
promiseArrs.forEach((item, index) => {
if (!isPromise(item)) {
result.push(item)
if (result.length === lengthNum) {
resolve(result)
}
} else {
try {
item.then(res => {
result.push(res)
if (result.length === lengthNum) {
resolve(result)
}
})
} catch (e) {
reject(e)
}
}
})
})
}
promise.all 其实挺好理解,通俗来讲就是等传入得所有异步操作完成后得一个回调,并拿到所有异步得返回值。
promise.race
promise.race,可以理解为赛跑,all是以谁执行的慢为标准,race就是以谁快为标准。
race接收一个可迭代参数,基本都是接收一个promise得数组,它会根据数组中第一个执行完成的promise为准则,不管执行的状态是成功还是失败(resolve,reject)。它和另外一个还未添加到标准中的方法 promise.any 不同的是,any 只会返回第一个成功的,失败的会被忽略。
promise.race的应用场景基本就是一些加载场景,控制并发量等,下面我们利用race实现一下同时加载数量,来控制一下并发量。
思考场景: 大量图片加载,此时除了懒加载的方式,我们还可以控制同时加载的数量,也就是控制并发量:
const images = [1,2,3,4,5,6,7,8,9,10,11,12]
const readFile = (url,index) => {
return new Promise((resolve, reject) => {
const time = Math.random().toFixed(4) * 10000
setTimeout(()=>{
console.log(`${url}加载完成`)
resolve(index)
},time)
})
}
const photoLimit = function (arrs, limit) {
if (!!arrs && Object.prototype.toString.call(arrs) === '[object Array]') {
const { length } = arrs
const imgslimit = arrs.splice(0, limit)
const promiseCont = imgslimit.map((item, index) => {
return readFile(item,index)
})
const runRace = function(arr) {
let cont = arr.filter(item => !!item)
return Promise.race(cont).then(i => {
if(arrs.length > 0) {
let url = arrs.pop()
promiseCont[i] = readFile(url, i) || null;
runRace(promiseCont)
} else {
console.log('没有待加载的了')
}
})
}
runRace(promiseCont)
} else {
return false
}
}
photoLimit(images, 3)
代码简单实现了并发限流,以及自动填充新任务的功能,完成一个补一个,没有过多考虑错误边界,定时器也没清除。有兴趣的同学,可以去优化。看一下输出:
that's all, thanks