【问题标题】:Javascript Promises chain with setTimeout calls not behave as expected [duplicate]带有 setTimeout 调用的 Javascript Promises 链未按预期运行 [重复]
【发布时间】:2021-10-17 18:42:15
【问题描述】:

我有以下代码来测试 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

我一直在寻找解决方案,我发现的最相似的是这个,尽管它并没有真正帮助我: Javascript Promises: then()'s aren't synchronous

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

【问题讨论】:

    标签: javascript asynchronous promise


    【解决方案1】:

    在承诺某事后,您不应该将回调传递给它 - 而是只在结果 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 被推断为传递的函数——cb 代表opA——它没有连接到 Promise,因此进一步的链接不起作用。使用 util 的 promisify,promisify 替换的回调应该是原始函数的最后一个参数 - 如果您将 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);
        });
    

    【讨论】:

      【解决方案2】:

      Promisify 删除了最后一个 callback 函数。意思是,通过print 方法在这里是无用。取而代之的是,您将在 then/resolve 函数中得到结果并打印。正如@CertainPerformance 所提到的,您可以转换为使用promise with print 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();

      【讨论】:

        猜你喜欢
        • 2014-10-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-06
        • 2020-04-10
        • 1970-01-01
        • 1970-01-01
        • 2017-10-23
        相关资源
        最近更新 更多