如何以正确的方式对不同承诺的执行流程进行排序以获得结果?

问题描述 投票:0回答:4

承诺链执行流程

Flow of the promise chain execution

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 在程序执行结束后被记录...

javascript promise settimeout
4个回答
2
投票

要按特定顺序解决承诺,您需要相应地链接它们。以下是其中一种方法的细分:

  1. 由于

    A
    D
    可以立即开始,我们调用
    timeoutPromise
    函数并将返回的promises保存在变量中,以便我们稍后引用它们。

  2. 因为我们需要在

    B
    解决后立即开始
    A
    ,我们可以在变量中保存对
    A
    承诺的引用,这样我们就可以在
    B
    完成时开始
    A

  3. 我们可以使用

    Promise.all
    等待
    A
    D
    解决后再开始
    C
    。结果承诺再次存储到变量中。

  4. 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();


0
投票

使用

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
返回的数据所必需的。


0
投票

这里有一些可怕的帖子🙃

下面

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)


-1
投票

除了 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);
© www.soinside.com 2019 - 2024. All rights reserved.