【问题标题】:Node JS: chaining promises which are using promisesNode JS:链接使用 Promise 的 Promise
【发布时间】:2017-05-25 19:50:10
【问题描述】:

我需要链接使用请求承诺的承诺,所以它有点链接嵌套的承诺。

想象一下代码:

const rp = require('request-promise');

function doStuff(){
  for ( let i = 0; i <= 10; i++ ){
    methodA();
  }
};

function methodA(){
  let options = {...};
  rp(options)
    .then(result => methodB(result))
    .catch(err => console.log(err));
};

function methodB(resultA){
  let options = {uri: resultA};
  rp(options)
    .then(result => methodC(resultA, result))
    .catch(err => console.log(err));
};

function methodC(resultA, resultB){
  //some calculations
};

在 doStuff 中,我需要等待方法 C 的所有十次执行的结果并将它们收集到数组中。我试过这样链接它:

function doStuff(){
  for ( let i = 0; i <= 10; i++ ){
    let promiseA = new Promise((resolve, reject) => {
      resolve(methodA());
    });
    let promiseB = promiseA.then(result => methodB(result));
    let promiseC = promiseB.then(result => methodC(promiseA.result, result));
    Promise.all([promiseA, promiseB, promiseC]);
  }
};

但它肯定行不通,因为在 methodA 和 methodB 中我们有异步的 HTTP 请求。因此,promiseB 中的结果是未定义的。

这意味着,问题是:如何链接承诺,如果它们有嵌套的承诺?(以及最终如何收集结果?)

谢谢!

更新:链接承诺也没有多大帮助,因为 1 返回 AB 的先前数组,但期望的结果反之亦然:

function methodA(){
    let promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('Resolved A');
            resolve('A');
        }, Math.random() * 2000);
    });

    return promise
        .then(result => methodB(result))
        .catch(err => console.log(err));
}

function methodB(resultA){
    let promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('Resolved B');
            resolve('B');
        }, Math.random() * 2000);
    });

    return promise
        .then(result => methodC(resultA, result))
        .catch(err => console.log(err));
}

function methodC(resultA, resultB){
    return resultA + resultB;
}

function doStuff() {
    let promises = [];

    for (let i = 0; i <= 10; i++){
        promises.push(methodA());
    }

    Promise.all(promises).then(results => {
        console.log(results);
    });
    return 1;
}

console.log(doStuff());

【问题讨论】:

标签: javascript node.js promise request-promise


【解决方案1】:

你的每个函数都需要返回它们的承诺:

function methodA(){
    let options = {...};
    return rp(options)
        .then(result => methodB(result))
        .catch(err => console.log(err));
}

function methodB(resultA){
    let options = {uri: resultA};
    return rp(options)
        .then(result => methodC(resultA, result))
        .catch(err => console.log(err));
}

function methodC(resultA, resultB){
    //some calculations
}

function doStuff() {
    let promises = [];
    for ( let i = 0; i <= 10; i++ ){
        promises.push(methodA());
    }
    Promise.all(promises).then(...)
}

编辑:我创建了一个测试示例,它在 methodAmethodB 中创建了 Promise。每个 Promise 都会持续 0 到 2 秒。它似乎正在工作:

function methodA(){
    let promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('Resolved A');
            resolve('A');
        }, Math.random() * 2000);
    });

    return promise
        .then(result => methodB(result))
        .catch(err => console.log(err));
}

function methodB(resultA){
    let promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('Resolved B');
            resolve('B');
        }, Math.random() * 2000);
    });

    return promise
        .then(result => methodC(resultA, result))
        .catch(err => console.log(err));
}

function methodC(resultA, resultB){
    return resultA + resultB;
}

function doStuff() {
    let promises = [];

    for (let i = 0; i <= 10; i++){
        promises.push(methodA());
    }

    return Promise.all(promises).then(results => {
        console.log(results);

        return 1;
    });
}

doStuff().then(result => {
    console.log(result);
});

【讨论】:

  • 很好,我没想到在methodB中做methodC
  • 没错,但在我无限的智慧中,我删除了它以使其更简单:D
  • @Felix Kling 我看到你在我的一秒后发布了相同的确切答案,然后将其删除。我要给你一个赞成票!
  • 好吧,你打败了我 :)
  • 也许只是更快的连接。我赞成你写得很好的另一个答案:)
【解决方案2】:

@Frank_Modica 的回答是正确的方法。

只想补充一点,如果您启用async/await,您可以这样做。但它确实需要BabelTypescript

async function myMethod() {
    const options = { }
    try {
        const result_a = await rp(options)
        const result_b = await rp({ uri: result_a })
        const result_c = ...
    } catch(err) {
        console.log(err)
    }
}

for (let i = 0; i <= 10; i++) {
    await myMethod();
}

【讨论】:

    【解决方案3】:

    它必须轻轻更改为:

    Promise.all([promiseA, promiseB, promiseC]).then([promiseD]);
    

    同样在函数本身中,它必须是一个返回语句才能使它们链接起来。对于请求本身,只需添加:{async: false}

    也可以使用:

    var runSequence = require('run-sequence');
    function methodA () {
        return runSequence(
            'promiseA',
            'promiseB',
            ['promiseC1', 'promiseC2'],
            'promiseD',
            callback
        );
    }
    

    【讨论】:

    • @KirillLinnik,但你试过用npmjs.com/package/sync-request 吗?
    • 它也无济于事,因为内部的 request-promise 导致链接嵌套了 promise。这意味着,我可以链,但由于嵌套的承诺,链是在函数 return 之外执行的
    猜你喜欢
    • 2022-06-22
    • 2018-08-19
    • 2017-10-08
    • 2020-10-22
    • 1970-01-01
    • 2017-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多