有这么一道问题:

let p1 = new Promise(resolve => {
  setTimeout(resolve('p1'), 1000)
})
let p2 = new Promise(resolve => {
  setTimeout(resolve('p2'), 500);
});
Promise.race([p1, p2])
  .then(value => {
    console.log(value)
  });

猜猜输出的会是什么?
大家可以试试看后面就明白,题目的本意是比较两个promise哪个更快,那么500毫秒的肯定更快,然而结果确是输出p1。为什么呢?
问题出在setTimeout上。
setTimeout的第一个参数,在执行到setTimeout语句的时候,就会执行。而resolve本身就是一个函数,当你带上了括号,它就立即执行了。而p1在p2之前,那么自然永远是p1先resolve了。所以,不管时间怎么改变,输出的永远是p1。

那么,正确的写法应该是什么呢?有两种解决方案:
一、setTimeout的第一个参数不要写成函数调用,而是写成函数的引用。
也就是:

setTimeout(resolve, 1000);

有朋友可能会问,那这样怎么传参呢?实际上,setTimeout支持第三个参数,我们可以这样传参。这也是Promise里经常能看到的调用方法:

setTimeout(resolve, 1000, "p1");

这样就只会在1秒后,才真正把参数传递到函数中并执行。
二、用一个匿名函数:

setTimeout(() => {
  resolve("p1");
}, 1000);

这样也能避免函数立即调用,而是在1秒后再调用。


感觉setTimeout是一个很神奇的函数,在学习js原理的时候,经常能看到它的身影。认真学习这个函数,有助于对js原理的理解。


Edward
54 声望3 粉丝

宁可十年不将军,不可一日不拱卒