Javascript 使用 setTimeout 调用的承诺链未按预期运行

Javascript Promises chain with setTimeout calls not behave as expected

我有以下代码来测试 Javascript 中的异步执行,使用承诺和超时:

'use strict'
const { promisify } = require('util')

const print = (err, contents) => { 
  if (err) console.error(err)
  else console.log(contents) 
}

const opA = (cb) => {
  setTimeout(() => {
    cb(null, 'A')
  }, 500)
}

const opB = (cb) => {
  setTimeout(() => {
    cb(null, 'B')
  }, 250)
}

const opC = (cb) => {
  setTimeout(() => {
    cb(null, 'C')
  }, 125)
}

const opAProm = promisify(opA)
const opBProm = promisify(opB)
const opCProm = promisify(opC)

opAProm(print).then((res) => opBProm(print).then((res) => opCProm(print)))

我期望的结果是这样的:

A
B
C

但是它只是这样打印的:

A

我一直在寻找解决方案,我找到的最相似的解决方案是这个,尽管它并没有真正帮助我:

所以我想知道如何解决这个问题,使用 promises 或 async/await。 提前致谢!

在 promise 之后,你不应该传递一个回调 - 而是只对结果 Promise 调用 .then。如果您从这些行中删除 prints:

opAProm(print)

而不是直接链接 Promise,它将按需要工作。

opAProm().then((resultA) => {
    print(resultA);
    opBProm().then((resultB) => {
        print(resultB);
        opCProm()
            .then((resultC) => {
                print(resultC);
            });
    })
});

或者,更好的方法:

opAProm()
    .then((resultA) => {
        print(resultA);
        return opBProm();
    }).then((resultB) => {
        print(resultB);
        return opCProm();
    })
    .then((resultC) => {
        print(resultC);
    });

(或使用async/await

否则,如果您这样做(就像在您的原始代码中一样)

opAProm(print)

然后 cb 被推断为传递的函数 - opAcb - 它未连接到 Promise,因此进一步的链接不起作用。使用 util 的 promisify,promise 替换的回调应该是原始函数的最后一个参数 - 如果您将 another 参数组合传递给它,它将摆脱困境。除非你改变原来的函数来接受两个参数,这真的很奇怪,但会“有效”。

const opA = (cb, finalcb) => {
    setTimeout(() => {
        cb(null, 'A')
        finalcb();
    }, 500)
}

const opB = (cb, finalcb) => {
    setTimeout(() => {
        cb(null, 'B')
        finalcb();
    }, 250)
}

const opC = (cb, finalcb) => {
    setTimeout(() => {
        cb(null, 'C')
        finalcb();
    }, 125)
}

const opAProm = promisify(opA)
const opBProm = promisify(opB)
const opCProm = promisify(opC)

opAProm(print)
    .then(() => {
        return opBProm(print);
    }).then(() => {
        return opCProm(print);
    });

Promisify 删除了最后一个 callback 函数。意思是,传递的 print 方法在这里 没用 。相反,您将在 then/resolve 函数中获得结果并打印。正如@CertainPerformance 提到的,您可以转换为使用 promise with then in then 或使用 async-await 来简化。

const { promisify } = require("util");

const print = (err, contents) => {
  if (err) console.error(err);
  else console.log(contents);
};

const opA = (cb) => {
  setTimeout(() => {
    cb(null, "A");
  }, 500);
};

const opB = (cb) => {
  setTimeout(() => {
    cb(null, "B");
  }, 250);
};

const opC = (cb) => {
  setTimeout(() => {
    cb(null, "C");
  }, 125);
};

const opAProm = promisify(opA);
const opBProm = promisify(opB);
const opCProm = promisify(opC);

async function main() {
  const resA = await opAProm();
  console.log(resA);
  const resB = await opBProm();
  console.log(resB);
  const resC = await opCProm();
  console.log(resC);
}
main();