是否可以链接setTimout功能以确保它们一个接一个运行?
是否可以在 JavaScript 中链接 setTimeout 函数?
IT技术
javascript
settimeout
                    2021-03-16 01:12:36
                
                    
                
            
        5个回答
            这里列出了三种不同的方法:
- 手动嵌套
setTimeout()回调。 - 使用可链接的计时器对象。
 - 包裹
setTimeout()在Promise和链Promise中。 
手动嵌套 setTimeout 回调
当然。当第一个触发时,只需设置下一个。
setTimeout(function() {
    // do something
    setTimeout(function() {
        // do second thing
    }, 1000);
}, 1000);
可链接的定时器对象
您还可以让自己成为一个小实用程序对象,它可以让您真正链接事物,让您可以像这样链接调用:
delay(fn1, 400).delay(fn2, 500).delay(fn3, 800);
function delay(fn, t) {
    // private instance variables
    var queue = [], self, timer;
    
    function schedule(fn, t) {
        timer = setTimeout(function() {
            timer = null;
            fn();
            if (queue.length) {
                var item = queue.shift();
                schedule(item.fn, item.t);
            }
        }, t);            
    }
    self = {
        delay: function(fn, t) {
            // if already queuing things or running a timer, 
            //   then just add to the queue
        	  if (queue.length || timer) {
                queue.push({fn: fn, t: t});
            } else {
                // no queue or timer yet, so schedule the timer
                schedule(fn, t);
            }
            return self;
        },
        cancel: function() {
            clearTimeout(timer);
            queue = [];
            return self;
        }
    };
    return self.delay(fn, t);
}
function log(args) {
    var str = "";
    for (var i = 0; i < arguments.length; i++) {
        if (typeof arguments[i] === "object") {
            str += JSON.stringify(arguments[i]);
        } else {
            str += arguments[i];
        }
    }
    var div = document.createElement("div");
    div.innerHTML = str;
    var target = log.id ? document.getElementById(log.id) : document.body;
    target.appendChild(div);
}
function log1() {
	  log("Message 1");
}
function log2() {
	  log("Message 2");
}
function log3() {
	  log("Message 3");
}
var d = delay(log1, 500)
    .delay(log2, 700)
    .delay(log3, 600)
将 setTimeout 包装在 Promise 和 Chain Promise 中
或者,由于现在是 ES6+ 中 promise 的时代,这里是使用 promise 的类似代码,我们让 promise 基础设施为我们进行排队和排序。您最终可以使用这样的用法:
Promise.delay(fn1, 500).delay(fn2, 700).delay(fn3, 600);
这是背后的代码:
// utility function for returning a promise that resolves after a delay
function delay(t) {
    return new Promise(function (resolve) {
        setTimeout(resolve, t);
    });
}
Promise.delay = function (fn, t) {
    // fn is an optional argument
    if (!t) {
        t = fn;
        fn = function () {};
    }
    return delay(t).then(fn);
}
Promise.prototype.delay = function (fn, t) {
    // return chained promise
    return this.then(function () {
        return Promise.delay(fn, t);
    });
}
function log(args) {
    var str = "";
    for (var i = 0; i < arguments.length; i++) {
        if (typeof arguments[i] === "object") {
            str += JSON.stringify(arguments[i]);
        } else {
            str += arguments[i];
        }
    }
    var div = document.createElement("div");
    div.innerHTML = str;
    var target = log.id ? document.getElementById(log.id) : document.body;
    target.appendChild(div);
}
function log1() {
    log("Message 1");
}
function log2() {
    log("Message 2");
}
function log3() {
    log("Message 3");
}
Promise.delay(log1, 500).delay(log2, 700).delay(log3, 600);
你提供给这个版本的函数可以是同步的,也可以是异步的(返回一个Promise)。
受到@jfriend00 的启发,我展示了一个较短的版本:
Promise.resolve()
  .then(() => delay(400))
  .then(() => log1())
  .then(() => delay(500))
  .then(() => log2())
  .then(() => delay(800))
  .then(() => log3());
function delay(duration) {
  return new Promise((resolve) => {
    setTimeout(() => resolve(), duration);
  });
}
function log1() {
  console.log("Message 1");
}
function log2() {
  console.log("Message 2");
}
function log3() {
  console.log("Message 3");
}
如果您使用面向 ES6 的 Typescript,这对于 Async Await 来说非常简单。这也非常易于阅读,并且对 promises 答案进行了一些升级。
//WARNING: this is Typescript source code
//expect to be async
async function timePush(...arr){
    function delay(t){
        return new Promise((resolve,reject)=>{
            setTimeout(()=>{
                resolve();
            },t)
        })
    }
    //for the length of this array run a delay
    //then log, you could always use a callback here
    for(let i of arr){
        //pass the items delay to delay function
        await delay(i.time);
        console.log(i.text)
    }
}
timePush(
    {time:1000,text:'hey'},
    {time:5000,text:'you'},
    {time:1000,text:'guys'}
);
我遇到了同样的问题。我的解决方案是通过调用 self setTimeout,它有效。
let a = [[20,1000],[25,5000],[30,2000],[35,4000]];
function test(){
  let b = a.shift();
  console.log(b[0]);
  if(a.length == 0) return;
  setTimeout(test,b[1]);
}
数组 a 中的第二个元素是要延迟的时间
async / await与@Penny Liu一起使用示例:
(async() => {
  await delay(400)
  log1()
  await delay(500)
  log2()
  await delay(800)
  log3()
})()
async function delay(duration) {
  return new Promise((resolve) => {
    setTimeout(() => resolve(), duration);
  });
}
function log1() {
  console.log("Message 1");
}
function log2() {
  console.log("Message 2");
}
function log3() {
  console.log("Message 3");
}
其它你可能感兴趣的问题