承诺链执行流程
const timeoutPromise = (interval, intervalName) => {
return new Promise((resolve, reject) => {
setTimeout(function(){
console.log(`Executed ${intervalName} at: ${new Date().toString()} with interval of ${interval}`);
resolve();
}, interval);
});
};
let main = () => {
console.log('Starting at:', new Date().toString());
console.log('Completed at:', new Date().toString());
};
从上面给定的图像中,创建一个将 2 个字段作为参数的函数: - 一封信(在我们的例子中是 A、B、C、D) - 以毫秒为单位的时间将是您提供的任何不同值
函数内部必须有一个setTimeout,其值为上述时间
main 函数将开始执行,这样上面创建的函数将按照上面指定的时间顺序执行,即: - A & D 将一起开始 - C 只会在 A & D 完成后开始 - B 将在 A 完成后立即开始
执行必须以这样的方式进行: - 程序执行开始时应在控制台中记录时间和消息 - 程序执行结束时应在控制台中记录时间和消息 - 每次调用函数时都应记录时间和字母
我尝试了所有可能的方法,但要么函数 A 运行了两次,要么 B 在程序执行结束后被记录...
要按特定顺序解决承诺,您需要相应地链接它们。以下是其中一种方法的细分:
由于
A
和D
可以立即开始,我们调用timeoutPromise
函数并将返回的promises保存在变量中,以便我们稍后引用它们。
因为我们需要在
B
解决后立即开始A
,我们可以在变量中保存对A
承诺的引用,这样我们就可以在B
完成时开始A
。
我们可以使用
Promise.all
等待A
和D
解决后再开始C
。结果承诺再次存储到变量中。
Promise.all
用于等待 B
和 C
承诺结算以确保在我们结束执行之前两个承诺都已结算。
运行示例:
const timeoutPromise = (seconds, intervalName) => {
return new Promise((resolve, reject) => {
setTimeout(function () {
console.log(
`Executed ${intervalName} at: ${new Date().toString()} with interval of ${seconds} seconds`
);
resolve();
}, seconds * 1000);
});
};
let main = () => {
console.log('Starting at:', new Date().toString());
const promiseA = timeoutPromise(1, 'A');
const promiseAandD = Promise.all([promiseA, timeoutPromise(4, 'D')]);
const promiseBThen = promiseA.then(() => timeoutPromise(1, 'B'));
const promiseCThen = promiseAandD.then(() => timeoutPromise(1, 'C'));
Promise.all([promiseCThen, promiseBThen]).then(
() => {
console.log('Completed at:', new Date().toString());
}
);
};
main();
使用
setTimeout
很可能不是实现一系列承诺的最佳方式。这是一个不同的方法,涉及一个 async
函数来帮助阐明执行顺序:
// helper function to create a promise:
function prom(name,delay){
return new Promise((res,rej)=>{
setTimeout(()=>{
console.log(`promise ${name}: ${delay}ms`);
res(name)}, delay);
});
}
async function main(){
let [d,a]=await Promise.all([prom("D",400),prom("A",200)]);
let [c,b]=await Promise.all([prom("C",300),prom("B",100)]);
console.log(`all done: ${[a,b,c,d].join(", ")}`)
}
main()
起初并行等待承诺 D 和 A。一旦它们被履行,承诺 C 和 B 就会并行等待。诚然,承诺 B 可以早一点开始,因为它不依赖于 D 的实现,但这最终不会真正产生重大差异。而且,为了代码易于阅读和理解,我认为这个解决方案就足够了。
更新
好的,这是另一个版本 - 稍微难读 - 允许 D 和 B 部分并行运行(B 可以在 A 解决后启动):
// helper function to create a promise:
function prom(name,delay,...args){
console.log(`starting ${name}, using arguments: [${args.join(", ")}].`);
return new Promise((res,rej)=>{
setTimeout(()=>{
console.log(`resolved ${name} after ${delay}ms`);
res(name)}, delay);
});
}
async function main(){
const [D,A] = [prom("D",2000),prom("A",1000)]; // define the promises D and A immediatey
const [c,b] = await Promise.all([ // await promises C and B ...
Promise.all([D,A]).then(args=>prom("C",2000,...args)), // define promise C after D and A are resolved
A.then(args=>prom("B",2000,...args)) ]);// define promise B after A is resolved
console.log(`All promises resolved, here is the data: ${await A}, ${b}, ${c}, ${await D}.`);
}
main()
.as-console-wrapper {min-height:100%}
不要被脚本末尾的
await A
和await D
给骗了:因为两个promise都已经解决了,所以这里没有额外的时间“等待”。 await
是访问承诺 a
和 d
返回的数据所必需的。
这里有一些可怕的帖子🙃
下面
work
是产生承诺值的通用函数。将 work
替换为任何产生承诺的功能。 run
编码依赖图 -
const work = value =>
new Promise(r => setTimeout(r, 1000, value))
async function run() {
const [a,d] = await Promise.all([work("A"), work("D")])
const ctask = work(a + d + "->C")
const btask = work(a + "->B")
return Promise.all([ctask, btask])
}
run().then(console.log).catch(console.error)
除了 Yousaf 的回答外,这里还有一个概括的尝试:
class PromiseAfter {
constructor(promise) {
this.promise = promise;
this.prereqs = [];
this.succcnt = 0;
}
after(p) {
this.prereqs.push(p);
p.succcnt++;
}
}
class Promises {
promises = [];
add(promise) {
var p = new PromiseAfter(promise);
this.promises.push(p);
return p;
}
execute() {
var promises = [];
while (promises.length < this.promises.length)
this.promises.filter(q => q.succcnt === 0).forEach(function(p) {
promises.unshift(p);
for (var q of p.prereqs) q.succcnt--;
p.succcnt = -1;
});
promises.forEach(function(p) {
p.promise = Promise.all(p.prereqs.map(q => q.promise)).then(p.promise);
});
return Promise.all(this.promises.map(q => q.promise));
}
}
个人承诺可以被
add
ed到一个Promises
实例,并且他们的after
方法被调用他们所依赖的每一个其他承诺。然后,execute
实例的 Promises
方法按必要的顺序执行它们。
function makePromise(x) {
return new Promise(function(resolve, reject) {
console.log(x, "starts");
setTimeout(function() {
console.log(x, "ends");
resolve(x);
}, 1000);
});
}
var p = new Promises();
var A = p.add(() => makePromise("A"));
var B = p.add(() => makePromise("B"));
var C = p.add(() => makePromise("C"));
var D = p.add(() => makePromise("D"));
B.after(A);
C.after(A);
C.after(D);
p.execute().then(console.log);