请帮助我解释为什么日志结果有两种不同之处:
方式1:每1秒按顺序记录
方式2:1秒后记录所有元素。
// Way 1
let sequence = Promise.resolve();
[1,2,3,4].forEach((val)=> {
sequence = sequence.then(()=> {
return new Promise(resolve => setTimeout(resolve, 1000, val))
}).then(console.log);
})
//Way 2
let sequence2 = Promise.resolve();
[5,6,7,8].map(val => {
return new Promise(resolve => setTimeout(resolve, 1000, val));
}).forEach(promise => {
sequence2 = sequence2.then(() => promise).then(console.log);
});
已修改:在方式2中错误地记录日志结果
答案 0 :(得分:1)
您已按照"方式1"对您的计时器进行了排序(它们各自相隔一秒)然后并行地运行你的计时器"方式2"所以计时器大约在同一时间点火。这里有更详细的解释:
在"方式1"中,您使用sequence = sequence.then()
创建一系列承诺,并从序列中调用setTimeout()
。因此,计时器2不会启动,直到计时器1发生之后,依此类推。你将使每个单独的计时器真正顺序运行,每次点火约1秒钟。
在"方式2"中,您在.map()
中同时启动所有计时器,因此所有计时器并行运行,而不是按顺序运行。然后,您尝试使用sequence2 = sequence2.then()
循环强制它们进入序列,但是异步操作已经并行启动,因此所有这些顺序循环并不能真正完成Promise.all()
以外的任何操作。在时间方面。
如果您运行这两个片段中的每一个,它们将在计时器触发时准确记录,您可以看到两者之间的差异。
这里,在"方式1"的版本中记录每个计时器的时间顺序,你可以看到计时器相隔1秒左右:
// way 1
let startTime = Date.now();
function log() {
let args = Array.from(arguments);
// calc time since startTime
let delta = (Date.now() - startTime) / 1000;
args.unshift(delta + ": ");
console.log.apply(console, args);
}
function delay(t, val) {
return new Promise(resolve => {
setTimeout(() => {
log("timer fire");
resolve(val);
}, t);
});
}
// Way 1
let sequence = Promise.resolve();
[1,2,3,4].forEach((val)=> {
sequence = sequence.then(()=> {
return delay(1000, val);
}).then(console.log);
});
sequence.then(() => {
log("all done");
})

这里,在"方式2"的版本中记录每个计时器的时间顺序,您可以看到计时器在同一时间点火:
// way 2
let startTime = Date.now();
function log() {
let args = Array.from(arguments);
// calc time since startTime
let delta = (Date.now() - startTime) / 1000;
args.unshift(delta + ": ");
console.log.apply(console, args);
}
function delay(t, val) {
return new Promise(resolve => {
setTimeout(() => {
log("timer fire");
resolve(val);
}, t);
});
}
//Way 2
let sequence2 = Promise.resolve();
[5,6,7,8].map(val => {
return new delay(1000, val);
}).forEach(promise => {
sequence2 = sequence2.then(() => promise).then(console.log);
});
sequence2.then(() => {
log("all done");
});

在运行每个代码段时,特别是没有时间到达"所有已完成"信息。第一个序列化四个一秒钟的定时器,所以它需要 运行约4秒钟。第二个并行运行所有计时器,因此运行大约需要1秒钟。
补充说明:
执行此操作时:
let arrayOfPromoises = [5,6,7,8].map(val => {
return new Promise(resolve => setTimeout(resolve, 1000, val));
});
该代码连续四次执行return new Promise(resolve => setTimeout(resolve, 1000, val));
,一个接一个地执行,没有延迟。因为每次执行该代码时,它都会创建一个新的Promise
对象,最终会得到一个包含四个promise的数组。
现在,在该代码中你有这个:
new Promise(resolve => setTimeout(resolve, 1000, val));
Promise执行程序函数(即传递给Promise构造函数的回调函数)被立即调用。没有等待。所以,你不仅创造了四个承诺,而且你也开始了四次同时运行。这些计时器已经开始了。使用sequence2 = sequence2.then()
循环进行任何数量的结构都不会改变这种情况。计时器已经在运行。
答案 1 :(得分:0)
要理解这一点,你需要明白承诺只是等待解决的事情,所以在得到解决方案之前,以下(.then)代码链不会执行
对于第一种方法,让我们使用不同的变量而不是相同的序列变量,然后代码变为。
var firstSequence = Promise.resolve()
.then(()=> {return new Promise(resolve => setTimeout(resolve, 1000, 1))})
.then(console.log);
var secondSequence = firstSequence
.then(()=> {return new Promise(resolve => setTimeout(resolve, 1000, 2))})
.then(console.log);
var thirdSequence = secondSequence
.then(()=> {return new Promise(resolve => setTimeout(resolve, 1000, 3))})
.then(console.log);
var foruthSequence = thirdSequence
.then(()=> {return new Promise(resolve => setTimeout(resolve, 1000, 4))})
.then(console.log);
从这里可以看出,在解析promise之前不会发生超时调用。所以它们似乎是连续的,并且它们不断被推迟等待一秒钟。
但第二种形式相当于此。
function makePromise(val) {
return new Promise(resolve => setTimeout(resolve, 1000, val));
}
var storageArray = [makePromise(1), makePromise(2), makePromise(3),
makePromise(4)];
我们已经将所有的setimout调用一起推送到一起,所以在一秒钟之后所有的承诺都已经解决了。所以(.then)不需要等待等等。
var firstSequence = Promise.resolve()
.then(()=> {return storageArray[0]})
.then(console.log);
var secondSequence = firstSequence
.then(()=> {return storageArray[1]})
.then(console.log);
var thirdSequence = secondSequence
.then(()=> {return storageArray[2]})
.then(console.log);
var foruthSequence = thirdSequence
.then(()=> {return storageArray[3]})
.then(console.log);
所以尽管它们似乎与第一个语法类似,但承诺都已经解决,因此无需等待。