Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

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

js时间段内并行执行多个方法?

我想实现的效果如下:
我有一个数组,数组内每个对象都有一个动画的起始时间和动画的执行时长。
在动画最开始的时候,会有一个总的计时时间,当当前计时满足数组内的动画起始时间的时候,数组的动画(某个方法)执行。
数组对象类似于:

[
    {start:2,duration:1,call:function(){}},//当计时到 2 秒的时候,执行一个动画(call),执行动画时间为 1 秒。
    {start:5,duration:3,call:function(){}},//当计时到 5 秒的时候,执行一个动画(call),执行动画时间为 3 秒。
    {start:7,duration:4,call:function(){}},//当计时到 7 秒的时候,执行一个动画(call),执行动画时间为 4 秒。
    {start:4,duration:10,call:function(){}}//当计时到 4 秒的时候,执行一个动画(call),执行动画时间为 10 秒。
]

动画最开始,开始计时,然后分别按规则执行数组对象内的方法。
类似于Flash时间轴的动画。

我想问一下,有没有类似的封装的比较好的插件,来处理这种setTimeout方法。

我现在能想到的实现就是每个对象都单独执行一个setTimeout方法,执行完清理掉。但是我感觉这种方法不方便,想咨询下各位有没有更好的解决方案。谢谢


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

1 Answer

0 votes
by (71.8m points)

动画就用专门的动画库来搞啦!
比如animejs这种。


同时调度多个对象,也无需用到并行这么高大上的概念,只要合理的任务调度就可以了,毕竟对 CPU 主核而言,所谓“并行”无非是对运算资源的调度,JS 作为一门图灵完备的语言,模拟这种任务调度自然不在话下。


追加一个使用 raf 实现的调度器:

const scheduler = (() => {
    const taskQueue = [];
    const { now } = Date;
    const { abs } = Math;
    const PRECISION = 16;  // 计时器精度
    let frame = null;
    
    const raf = () => {
        frame = requestAnimationFrame(() => {
            const moment = now();
            const markAsDelete = [];
            for(let index in taskQueue){
                const [task, time] = taskQueue[index];
                
                // 需要根据实际需求确定合适的回调执行条件
                if(abs(time - moment) < PRECISION){
                    task();
                    markAsDelete.push(index);
                }
            }
            
            // 删除执行过的任务
            markAsDelete.reverse().forEach(item => {
                taskQueue.splice(item, 1);
            });
            
            // 递归执行调度
            if(!!taskQueue.length){
                raf();   
            } else {
                frame = null;
            }
        });
    }
    
    // 启动调度
    raf();
    
    return {
        // 这里采用的是类似 setTimeout 的接口设计,
        // 但实际应用中可以采用其他形式的接口,配合
        // raf 中的判断条件,可以形成更加丰富的调度
        // 方案,比如注册速度来达到对速度的控制等
        register(task, timeout){
            const moment = now();
            taskQueue.push([task, timeout + moment]);
            if(frame === null){
                raf();
            }
            return this;
        }
    }
})();

根据你的需求可以这样写:

// 每个任务需要用一个函数启动、一个函数停止
const taskArray = [
    {
        start: 2,
        duration: 4,
        startFn: () => {},
        stopFn: () => {}
    }
    // ...
];
taskArray.forEach(item => {
    const {start, duration, startFn, stopFn} = item;
    scheduler.register(startFn, start * 1000)
    .register(stopFn, (start + duration) * 1000);
});

但看起来和用 setTimeout 也差不多。。。


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...