借助Iterable object(可迭代对象)实现Promise并发控制
什么是Iterator object
可迭代(Iterable) 对象是数组的泛化
也就是说、任何对象都可以通过迭代器来使用 for...of语法来循环遍历
举个例子:
我们常见的数组、数组本身就具有循环遍历的能力
//假如我有很多个女朋友
var girlFriends=["alice","lina","rose"];
//我想知道她们的名字
for(var girlFriend of grilFriends){
console.log(girlFriend)
}
//原来我有三个女朋友
//output:alice lina rose
迭代对象不仅仅限于数组,比如我们自定义一个对象,那么如何在自定义对象上使用迭代器呢?
方法如下:
如何构建一个Iterator object
可迭代对象、简单的来说就是给对象添加一个Symbol.iterator方法、该方法返回一个含有next方法的对象,如下代码展示
var obj={};
//当`for..of`执行的时候、首先会执行该方法,该方法放回的对象、则就是迭代器
obj[Symbol.iterator]=function(){
return {
next:function(){
//next方法返回一个含有done属性的对象、用于标记循环是否结束、还有一个value属性、用于返回当前的值
return {
done:true
value:''
}
}
}
}
当for..of执行的时候、会执行Symbol.iterator方法,获取到迭代器。后面的循环都将使用该迭代器就行遍历
var girlFriendAgeRange= {
min: 18,
max: 100,
};
//我希望每个年龄的都有一个
//for(var age in girlFriendAgeRange)
//输出:18,19,20...100
根据上文说到的、定义一个Symbol.iterator方法
var girlFriendAgeRange = {
min: 18,
max: 100,
};
girlFriendAgeRange[Symbol.iterator] = function () {
return {
//由于next的执行上下文、是当前对象、所以我们把我们需要的数据、绑定到当前上线文、便于后续使用
current: this.min,
max: this.max,
next: function () {
if (this.current <= this.max) {
return { done: false, value: this.current++ };
} else {
return { done: true };
}
},
};
};
for (var age of girlFriendAgeRange) {
console.log(age);
}
//这样我们就有很多个女朋友了
迭代器总的来说、就是这么简单
如何用迭代器对象来控制Promise的并发限制呢
前面说的迭代器都是自动运行的情况、还有一中情况、我们可以手动控制迭代器的访问,比如:
//我们有三个女朋友
var girlFriends=["alice","lina","rose"];
//我们知道数组是含有迭代器对象的、所以我们直接获取到就行
var iterator = girlFriends[Symbol.iterator]();
let first=iterator.next();
console.log(first.value)//输出alice
let second=iterator.next();
console.log(first.value)//输出lina
所以可以通过手动控制迭代器对象的访问的方式来实现一个Promise的并发限制
直接上代码:
//模拟10个异步请求
var data = new Array(10).fill("").map((item, i) => {
let index = i;
return function (callback) {
console.log(index + " promise start");
setTimeout(() => {
console.log(index + " promise end");
callback();
}, Math.random() * 8000);
};
});
class PromisePool {
constructor(promise, queueSize) {
this.promise = promise;
this.queueSize = queueSize || 5;
this.count = 0;
this.iterator = this.promise[Symbol.iterator]();
}
request(fn) {
fn(() => {
this.count--;
this.run();
});
}
run() {
if (this.count < this.queueSize) {
let next = this.iterator.next();
if (!next.done) {
this.count++;
this.request(next.value);
this.run();
}
} else {
console.log("wait a promise done ");
}
}
}
new PromisePool(data, 5).run();
//输出
0 promise start
1 promise start
2 promise start
3 promise start
4 promise start
wait a promise done
1 promise end
5 promise start
wait a promise done
5 promise end
6 promise start
wait a promise done
3 promise end
7 promise start
wait a promise done
7 promise end
8 promise start
wait a promise done
4 promise end
9 promise start
wait a promise done
2 promise end
8 promise end
9 promise end
0 promise end
6 promise end
总结
- 可以使用for..of的对象、是可迭代的
- 可迭代对象必须实现
Symbol.iterator方法 Symbol.iterator方法返回的对象称为迭代器迭代器需要含有next方法Symbol.iterator方法会被for..of自动调用,也可以手动调用