当我使用承诺时,我仍然会得到厄运金字塔,我做错了什么?



我正在使用Node.js的询问者库,当使用承诺时,我仍然得到厄运金字塔,我做错了什么?

仅供参考,查询库API基本上是:

inquirer.prompt([
question1,
question2,
question3,
...
questionX
]).then(function(answers){});

中的答案是一个散列,其中的键代表每个问题。这里没什么特别的。

无论如何,使用API,我总是得到getAnswersToPrompts().then(function(answers){}),它似乎更方便保持嵌套承诺在前一个…像这样:

function run (rootDir) {
  return watchHelper().then(function (answers) {
    return chooseDirs({
      allowDirs: answers.allow,
      originalRootDir: rootDir,
      onlyOneFile: false
    }).then(function (pathsToRun) {
      assert(pathsToRun.length > 0, ' You need to select at least one path.');
      return getOptions(availableOptionsForPlainNode).then(function (answers) {
        const selectedOpts = answers[ 'command-line-options' ];
        return localOrGlobal().then(function (answers) {
          const sumanExec = answers.localOrGlobal;
          console.log(' => ', colors.magenta.bold([ '$', sumanExec, '--watch', pathsToRun, selectedOpts ].join(' ')));

        });
      });
    });
  }).catch(rejectionHandler);
}

我可以这样做:

function run(){
  return makePromise()
    .then(fn1(data1))
    .then(fn2(data2))
    .then(fn3(data3))
}

其中fn1,fn2,fn3如下:

function fnX(data){
   return function(answers){
      return promise(data);
   }
}

但是这只会让理解AFAICT变得更复杂

请尽可能清楚,我肯定需要前一个承诺的结果,但有时我需要更早于承诺的结果,甚至更早于承诺的结果。

嵌套函数允许我需要的数据在范围内,感谢闭包等。

在调用then:

之前返回下一个Promise
function run (rootDir) {
  var pathsToRun;
  return watchHelper()
    .then(function (watchHelperAnswers) {
      return chooseDirs({
        allowDirs: watchHelperAnswers.allow,
        originalRootDir: rootDir,
        onlyOneFile: false
      });
    }).then(function (chooseDirsResult) {
      assert(chooseDirsResult.length > 0, ' You need to select at least one path.');
      pathsToRun = chooseDirsResult;
      return getOptions(availableOptionsForPlainNode);
    }).then(function (getOptionsAnswers) {
      const selectedOpts = getOptionsAnswers[ 'command-line-options' ];
      return localOrGlobal();
    }).then(function (localOrGlobalAnswers) {
      const sumanExec = localOrGlobalAnswers.localOrGlobal;
      console.log(' => ', colors.magenta.bold([ '$', sumanExec, '--watch', pathsToRun,
        selectedOpts ].join(' ')));
    }).catch(rejectionHandler);
}

但有时我需要promise的结果在那之前或者甚至是结果在那之前

在你的例子中唯一的实例是pathsToRun。我认为嵌套函数两到三个深度来适应这仍然是可读的,但是你的另一个选择是在承诺链之外定义一个变量,我在上面为pathsToRun展示了这一点。

最后,您的示例在整个承诺链中使用了三个不同的变量,都称为answers,这可能会增加混乱。一般来说,我认为对承诺回调结果使用相同的名称是可以的,但为了清晰起见,我在这里重新命名了它们。

@Joe Daley的答案近乎完美,但要再添加一件事。我真的不喜欢对函数顶部的变量赋值。我从来不喜欢async.waterfall/async.series……我也不喜欢承诺……下面的模式应该可以避免这种情况。我们在每个promise回调中积累数据,然后在最后一个promise回调中获得所有数据。

//start 
    function run (rootDir) {
    
      return watchHelper()
         .then(watchHelperAnswers => {
          
          return chooseDirs({
            allowDirs: watchHelperAnswers.allow,
            originalRootDir: rootDir,
            onlyOneFile: false
          });
    
        })
        .then(chooseDirsResult => {
        
         return getOptions(availableOptions).then((options) => {
              return {       //accumulate answers
                 options: options,
                 pathsToRun: chooseDirsResult
               }
         });
      
        })
        .then((obj) => {
          
          return localOrGlobal().then(answers => {
                return Object.assign(obj,{   //accumulate answers
                     localOrGlobal: answers.localOrGlobal
                  });
          });
        
        }).then((obj) => {
          
          const {...allTheAnswers} = obj;
        }).catch(rejectionHandler);
    }

繁荣!现在您可以避免对顶部的变量进行尴尬的赋值了。如果你不明白这是怎么回事……问我。

最新更新