正确的承诺链

时间:2017-10-03 07:15:29

标签: javascript asynchronous promise

我正在使用Chrome扩展程序,我需要使用Chrome消息通过后台脚本从页面扩展程序代码进行联系。这为我的代码添加了一个公平的异步。一般目的是使用存储在可从后台脚本访问的数据库中的数据来处理文本宏,即解析文本。

在某些时候,我有:

findMacro(key)
.then(result => {
   processMacro(key, result);
}};

处理器大致如下:

function processMacro(shortcut, text) {
  text = macroBuilder(text);
}

macroBuilder函数处理各种类型的宏,将处理后的文本推送到数组然后运行连接('')。我的问题是,我需要支持嵌套宏,当有这样的宏时,我再次调用findMacro,里面的chrome sendMessage会进入后台进程。处理器执行类似的操作:

function macroBuilder(text) {
  let pieces = [];
  macroProcessorCode(text).forEach(res => {
    res.visit({
      text(txt, ctx) {
        pieces.push(txt);
      },
      dates(obj, ctx) {
        pieces.push(processDates(obj))
      },
      ...
      nested(obj,ctx) {
        let fragments = [];
        fragments.push(
          findMacro(obj.name)
          .then(res => {
            return macroBuilder(res);
          })
        );
        console.log('promised results:', fragments);
        Promise.all(fragments)
        .then(fragments => {
          console.log('resolved results:', fragments);
          pieces.push(fragments);
        });
      }
    });
  });
  return pieces.join('');
}

由于某些原因,我的函数在解析之前返回,因此promised results在返回之前发生,而resolved results之后发生。简而言之,在处理嵌套宏之前,我从结果中返回代码处理文本。这只发生在嵌套的情况下,其他类型的宏被正确处理。

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

macroBuilder创造了许多承诺但从未对它们做任何事情。相反,它需要等待它们并返回它自己的承诺,它将根据片段/片段的承诺来解决/拒绝。

这有些偏离袖口,可能需要调整,但应该让你朝着正确的方向前进。请参阅***评论:

function macroBuilder(text) {
    // *** An array for all the promises below
    const piecePromises = [];
    macroProcessorCode(text).forEach(res => {
        res.visit({
            text(txt, ctx) {
                pieces.push(txt);
            },
            dates(obj, ctx) {
                pieces.push(processDates(obj))
            },
            //...
            nested(obj, ctx) {
                let fragments = [];
                fragments.push(
                    findMacro(obj.name)
                    .then(res => macroBuilder) // *** Note we can just pass `macroBuilder` directly
                );
                console.log('promised results:', fragments);
                // *** Add this promise to the array
                pieces.push(Promise.all(fragments)
                    // (*** This whole then handler can be removed
                    // once you don't need the logging anymore;
                    // just push the result of Promise.all)
                    .then(fragments => {
                        console.log('resolved results:', fragments);
                        return fragments;
                    })
                );
            }
        });
    });
    // *** Wait for all of those and then join; ultimate result
    // is a promise that resolves with the pieces joined together
    return Promise.all(piecePromises).then(pieces => pieces.join(''));
}

那时候processMacro没有多大意义;它看起来就像这样(注意它会返回一个承诺):

function processMacro(shortcut, text) {
  return macroBuilder(text);
}

...除非您使用shortcut执行了某些您尚未展示的内容。

假设您需要processMacro,如果您将承诺传播给来电者,则可以这样称呼它:

return findMacro(key)
.then(result => processMacro(key, result));

...或者如果你没有传播承诺,那就这样:

findMacro(key)
.then(result => processMacro(key, result))
.catch(err => {
   // Deal with the fact an error occurred
});

由于承诺规则之一是您传播承诺或处理错误。