【问题标题】:Deferred.notify() inside async.whilst() doesn't trigger progress handler until callbackasync.whilst() 中的 Deferred.notify() 在回调之前不会触发进度处理程序
【发布时间】:2017-05-13 09:54:43
【问题描述】:

我有一个返回承诺的函数(使用 Q),并且通知似乎没有在正确的时间发生。 onFulfilled 和 onRejected 回调按预期工作,但进度回调直到 async.whilst() 完成运行后才会触发,并立即触发所有内容。

这是函数

function generateSentences(data, num, options) {
    var deferred = Q.defer();
    const markov = new Markov(data, options);
    markov.buildCorpus()
        .then(() => {
            var count = 0;
            async.whilst(
                function () { return count < num; },
                function (callback) {
                    markov.generateSentence()
                        .then(result => {
                            console.log("Count: " + count);
                            deferred.notify(count / num); //update progress
                            count++;
                            callback(null);
                        }, (err) => {
                            deferred.reject(err.toString());
                            count++;
                        });
                },
                function (err, n) {
                    //PROGRESS EVENTS DON'T HAPPEN UNTIL HERE
                    deferred.resolve(generatedSentences); //finish
                }
            );
        }, (err) => console.log(err));
    return deferred.promise;
}

这是使用承诺

function generateScript() {
    fs.readdir(parser.videoBasePath, function (err, files) {
        parseFiles(files, parser.parse).then((a) => {
            console.log("Total Lines: " + fullScript.length + "\n");
            fullScript = _.shuffle(fullScript);
            markov.generateSentences(fullScript, 20).then((data) => {
                console.log(data);
            }, (err) => {
                console.log(err);
            }, (progress) => {
                console.log(progress);
            });
        });
    });
}

我读过一些类似 this 的帖子说我需要在 notify() 周围包裹一个 setTimeout,但它似乎没有任何影响。

【问题讨论】:

  • 对于诊断,如果您在创建deferred 后立即在generateSentences() 中注册一个进度回调,它的行为与您现有的进度回调相同还是不同?
  • 也许这就是为什么混合 Promises 和 async 被认为是Bad Thing To Do
  • @Roamer-1888,刚刚尝试过,它的行为与现有回调相同。我不知道混合承诺和异步是不好的做法,这是我第一次尝试 nodejs 项目。话虽如此,我尝试了另一种解决方案,消除了对异步的需求,但仍然遇到同样的问题
  • 这很奇怪,我无法解释这种行为,也无法理解为什么@JaromandaX 的答案不起作用 - 他的代码看起来不错。也许microtask vs macrotask 级别存在问题。我最好的建议是放弃async.jsQ/.notify(),转而采用更简单的方法将“通知”回调传递给generateSentences()

标签: node.js promise q async.js


【解决方案1】:

我读过 Promises + async.js 不能混合使用(但找不到任何话要说!!),我真的不明白为什么在这种情况下这应该是一个问题诚实的

话虽如此,您显示的代码似乎可以不用异步,所以试试这个看看进度是否更好

function generateSentences(data, num, options) {
    var deferred = Q.defer();
    const markov = new Markov(data, options);
    const genSentence = count => markov.generateSentence()
        .then(result => {
            console.log("Count: " + count);
            deferred.notify(count / num); //update progress
            if (count < num) {
                return genSentence(count + 1);
            }
        });
    markov.buildCorpus()
        .then(() => genSentence(0))
        .then(() => deferred.resolve(generatedSentences)) //finish
        .catch(err => deferred.reject(err.toString()));
    return deferred.promise;
}

至少,代码(在我看来)还是更简洁一些

【讨论】:

  • 绝对干净,谢谢。我已经尝试过您的解决方案hee,但我似乎仍然遇到了同样的问题。我注意到的一件事是,如果我注释掉“return genSentence”行以仅循环运行一次,则进度回调可以正常工作。这让我相信 notify() 不喜欢我们如何实现它的递归性质,以及 async.js 如何实现它?
  • 从来都不是 Promise 进度的“粉丝”——一些早期的实现有它,我什至修改了一个相当受好评的 Promise 实现以包含“进度链”——但最后,从未真正看到对它的需求——这似乎是一般 Promises 的方式
  • 我的问题有什么解决方法吗?承诺进度似乎是唯一适合我的用例。
  • 在我的脑海中,事件调度/监听对于进度通知很有用
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-16
  • 1970-01-01
  • 1970-01-01
  • 2019-02-24
相关资源
最近更新 更多