Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
365 views
in Technique[技术] by (71.8m points)

防抖(debounce)处理时,如何传回不同参数?

我有一个接口,传入id,传出value;
由于多处需要使用到这个接口,我就想到可以把这些id拼接后,进行请求再进行分发;

const set = new Set();
let timer;
function collect(idList) {
  return new Promise((resolve, reject) => {
    idList.forEach((id) => {
      set.add(id);
    });
    clearTimeout(timer);
    timer = setTimeout(async () => {
      const valueList = await getValue();
      resolve(
        valueList
          .filter((item) => idList.includes(item.id))
          .map((item) => item.value)
      );
    }, 300);
  });
}

// 模拟请求
function getValue() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(Array.from(set).map((id) => ({ id, value: id + '' })));
    }, 300);
  });
}

collect([1, 2, 3, 4]).then((list) => {
  console.log(list);
});
collect([1, 3, 5, 7]).then((list) => {
  console.log(list);
});
collect([9, 8, 7, 6]).then((list) => {
  console.log(list);
});

// 期望输出
// ['1', '2', '3', '4'] 
// ['1', '3', '5', '7']
// ['9', '8', '7', '6']

// 实际输出
// ['9', '8', '7', '6']

我是这么写的,但是这样的话 resolve 就被 clearTimeout 清除了。
这种情况下,应该怎么处理?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

这里我们需要 Deferred 对象来处理,就会简单很多。

简单分析,我们需要两步,第一步压入待发送请求,第二步合并参数使用一个请求发送。你需要的 debounce 效果就是,每次做第一步动作的时候都起一个定时器去做第二步。


// 我们需要把 Promise 对象转换成 Deferred 对象
// 因为需要在外部 resolve / reject promise
class Deferred {
  constructor() {
    this.promise = new Promise((res, rej) => {
      this.resolve = res;
      this.reject = rej;
    });
  }
}

class IdFetchTaskRunner {
  constructor() {
    this.tasks = [];
  }

  createTask(idList) {
    // 有一位乘客要上车
    const deferred = new Deferred();
    // 售票员车票存根,下车叫你要用
    this.tasks.push({ idList, deferred });
    // 返回给你的车票
    return deferred.promise;
  }

  async execute() {
    const tasks = this.tasks;
    // 发完车清空座位,下一波要用
    this.tasks = [];

    try {
      // 以下是本次发车过程
      const set = new Set(tasks.reduce((idList, task) => {
        return idList.concat(task.idList);
      }, []));

      const valueList = await getValue(set);
      // 转换成 map 处理
      const valueMap = valueList.reduce((m, item) => {
        m[item.id] = item.value;
        return m;
      }, {});
      // 遍历 tasks 依次 resolve ,(到站了,让每位乘客下车)
      tasks.forEach(task => {
        return task.deferred.resolve(task.idList.map(id => valueMap[id]));
      });
    } catch(e) {
      //(车抛锚了,让每位乘客下车)
      tasks.forEach(task => task.deferred.reject(e));
    }

  }
}

let taskRunner = new IdFetchTaskRunner();
let timer;
function collect(idList) {
  // 等等我,我也要上车
  clearTimeout(timer);
  // ok,重新算时间,300 ms 后发车,赶紧上
  timer = setTimeout(() => taskRunner.execute(), 300);
  // 这是你的车票拿好了
  return taskRunner.createTask(idList);
}

// 模拟请求,改为发送入参
function getValue(set) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(Array.from(set).map((id) => ({ id, value: id + '' })));
    }, 300);
  });
}

collect([1, 2, 3, 4]).then((list) => {
  console.log(list);
});
collect([1, 3, 5, 7]).then((list) => {
  console.log(list);
});

setTimeout(() => {
  // 同一拨
  collect([3, 8, 1, 6]).then((list) => {
    console.log(list);
  });
}, 100);

setTimeout(() => {
  // 这块赶不上了,只能下一波发车了
  collect([1, 1, 2, 1]).then((list) => {
    console.log(list);
  });
}, 800);

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...