如何写一个阻塞的 javascript 方法,如果有其他正在调用则被阻塞直到前一次方法调用完成才执行。
var foobar = function(){
setTimeout(function(){ console.log("hello"); },2000);
}
for(let i = 0;i< 1000; i++){
foobar();
}
比如我想让上面的for循环每2000ms才执行一次循环
如何写一个阻塞的 javascript 方法,如果有其他正在调用则被阻塞直到前一次方法调用完成才执行。
var foobar = function(){
setTimeout(function(){ console.log("hello"); },2000);
}
for(let i = 0;i< 1000; i++){
foobar();
}
比如我想让上面的for循环每2000ms才执行一次循环
一般程序不需要主动阻塞,这样会使程序变得低效,不能充分利用cpu时间,阻塞的场景一般都是IO调用如网络请求等。如果需要主动阻塞,通常是逻辑设计有问题。
如果是需要顺序调用接口,前一次接口调用返回后再调用下一个接口,建议可以这样改逻辑:
(async () => {
let r1 = await fetch('http://api.example.com/api1')
// 处理你的第一次请求
let r2 = await fetch('http://api.example.com/api2')
// 处理你的第二次请求
})()
fetch('http://api.example.com/api1').then(r => {
// 处理你的第一次请求
return fetch('http://api.example.com/api2')
}).then(r => {
// 处理你的第二次请求
})
fetch('http://api.example.com/api1', r1 => {
// 处理你的第一次请求
fetch('http://api.example.com/api2', r2 => {
// 处理你的第二次请求
})
})
如果不关系请求返回,可以将请求做成发送队列,调用的位置不要直接发请求,而是将请求和请求参数作为一个任务加入到发送队列中,然后在队列中完成发送
看了楼上的评论区才知道你的需求。。。正确的提问方式应该是把这个需求描述放到问题中去,这样回答者能够给你更好、更直接的解决方案。
比如你这个单信道复用的实现,最好的方案就是设置一个缓冲队列,每次有数据要发送时,并不是直接去调用发送数据的方法,而是把数据写入缓冲队列,等前一个请求完成的时候,把队列最前面的数据发送出去。
以等待2秒为例,差不多就是这样实现:
const addTask = (function(){
const taskQueue = [];
let pendingFlag = false;
function handler(task){
setTimeout(() => {
task();
consumer();
}, 2e3);
}
function consumer(){
if(!taskQueue.length){
pendingFlag = false;
return
}
handler(taskQueue.shift());
}
return function addTask(task){
taskQueue.push(task);
if(!pendingFlag) {
pendingFlag = true;
consumer();
}
}
})();
for(let i = 0;i< 10; i++){
addTask(() => console.log(`这是第${i + 1}个任务`));
}
但上面这是一个定制性的方案,每管理一种任务就需要完整地抄一遍,为了避免这种重复,我们可以写一个更加通用的解决方案:
function queueGen(processor){
const taskQueue = [];
let pendingFlag = false;
async function handler([param, callback, errorHandler]){
try{
callback(await processor(param));
} catch(err) {
if(errorHandler){
errorHandler(err)
}
}
consumer();
}
function consumer(){
if(!taskQueue.length){
pendingFlag = false;
return
}
handler(taskQueue.shift());
}
return function addTask(callback, param, errorHandler){
taskQueue.push([param, callback, errorHandler]);
if(!pendingFlag) {
pendingFlag = true;
consumer();
}
}
}
const addTask = queueGen(function asyncTimeOut(delay = 1e3){
return new Promise(function(resolve, reject){
setTimeout(resolve, delay)
});
});
for(let i = 0;i< 10; i++){
const delay = (10 % i) * 1e8
addTask(() => console.log(`第${i + 1}个任务,延迟了${delay}毫秒`), delay);
}
剩下的任务就是把你的通信接口写成 Promise
风格交给 queueGen
处理一下,然后随时随地 addTask
就行了。
8 回答4.3k 阅读✓ 已解决
6 回答2.7k 阅读✓ 已解决
5 回答2.4k 阅读✓ 已解决
6 回答2k 阅读
5 回答6.1k 阅读✓ 已解决
4 回答2.1k 阅读✓ 已解决
3 回答2.3k 阅读
你的意思就是js实现睡眠吧
同步版本
异步版本