我的JavaScript数据加载承诺中需要`setTimeout(resolve)`吗?

时间:2019-08-01 09:27:43

标签: javascript vue.js es6-promise

我试图通过不仅仅从howto文章中获取简单的示例代码来理解ES6 Promises,而且还试图将所学到的概念实现为对实际项目可能有用的代码。

下面,我在前端Vue.js / axios中创建了代码,该代码成功使用Promises向屏幕的五个区域加载数据。在我的后端loadData动作中,我故意将其等待一秒钟,因此我可以看到屏幕的五个区域中的每个区域都以一秒钟的间隔加载数据:

<div id="app" class="pageContent">
    <div>Data 1: {{data1}}</div>
    <div>Data 2: {{data2}}</div>
    <div>Data 3: {{data3}}</div>
    <div>Data 4: {{data4}}</div>
    <div>Data 5: {{data5}}</div>
</div>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            data1: 'loading...',
            data2: 'loading...',
            data3: 'loading...',
            data4: 'loading...',
            data5: 'loading...'
        },
        methods: {
            initialize: function () {
                const that = this;
                this.loadData('data1')
                    .then(() => {
                        return that.loadData('data2');
                    })
                    .then(() => {
                        return that.loadData('data3');
                    })
                    .then(() => {
                        return that.loadData('data4');
                    })
                    .then(() => {
                        return that.loadData('data5');
                    });
            },
            loadData: function (idCode) {
                return new Promise((resolve, reject) => {
                    const that = this;
                    axios({
                        method: 'post',
                        url: 'controllerShowcaseLoadDataWithPromises',
                        data: {
                            action: 'loadData',
                            idCode: idCode
                        }
                    }).then(function (responseObject) {
                        const response = qsys.getResponse(responseObject);
                        that[idCode] = response.data.message;
                        setTimeout(resolve);
                    });
                });
            },
        }
    });
    app.initialize();

虽然这似乎可以很好地工作,但是谁能解释为什么我必须使用setTimeout(resolve)(如果没有它,代码只能执行一次),这实际上是什么?我了解这基本上是我们兑现承诺之前的execute a callback的方式,但是什么是更清洁,更标准的方式呢?

2 个答案:

答案 0 :(得分:1)

  

...为什么我必须使用setTimeout(resolve)

您不必使用setTimeout,但是您必须致电resolve(或reject)来兑现承诺。

  

这里到底要去哪里?

您正在执行一系列异步调用,因为您已将诺言链接在一起,所以要等到上一个完成之后再执行下一个。这就是为什么如果您不解决第一个问题,那么其他任何一个都不运行的原因:您已链接了各个操作,因此在每种情况下,只有在成功完成上一个操作的情况下,才能运行下一个。如果您不调用resolve,则尽管操作已完成,但您永远不会履行所创建的承诺,而是使用该承诺来让代码完成操作。

  

我了解这基本上是执行承诺之前的回调方法,但是什么是更干净,更标准的方法?

如果必须显式创建一个Promise,则调用resolve是标准方法。 但是,在这种情况下您不必这样做,因为您已经有了axios的承诺。因此loadData应该是:

loadData: function(idCode) {
    return axios({
        method: 'post',
        url: 'controllerShowcaseLoadDataWithPromises',
        data: {
            action: 'loadData',
            idCode: idCode
        }
    }).then(function (responseObject) {
        const response = qsys.getResponse(responseObject);
        this[idCode] = response.data.message;
    });
},

请注意,它返回根据then的承诺调用axios的结果。 (还请注意,由于您正在使用箭头功能,因此不需要that = this。箭头功能 close over this。)

如果您希望您的操作一个接一个地执行,那么您的诺言链就是您的操作方式,尽管您可以根据需要更简洁地编写它,并且应该处理错误(同样,不需要{{1 }}):

that = this

如果您希望并行执行 (重叠)这五个操作,则可以立即启动它们,并使用this.loadData('data1') .then(() => this.loadData('data2')) .then(() => this.loadData('data3')) .then(() => this.loadData('data4')) .then(() => this.loadData('data5')) .catch(error => { // handle/report error here }); 等待所有操作完成:

Promise.all

最后,根据您的目标浏览器以及是否要转换,您还可以使用Promise.all([ this.loadData('data1'), this.loadData('data2'), this.loadData('data3'), this.loadData('data4'), this.loadData('data5'), ]) .catch(error => { // handle/report error here }); 函数和async

await

答案 1 :(得分:0)

一种现在做的“更清洁”的方法是将所有的Promise添加到数组中,并使用Promise.all

const requests = [
    that.loadData('data1'),
    that.loadData('data2'),
    that.loadData('data3'),
    that.loadData('data4'),
    that.loadData('data5')
];

Promise.all(requests).then(value => {
    // All resolved values in order
}).catch(error => {
    // Error
});

您的loadData函数仅在您不承诺resolve时才执行一次的原因恰恰是因为您没有解决承诺。 then从未在您的链中执行。

无需将resolve包裹在setTimeout中。