在我的JavaScript数据加载承诺中,我需要`setTimeout(resolve)`什么?

在我的JavaScript数据加载承诺中,我需要`setTimeout(resolve)`什么?,javascript,vue.js,es6-promise,Javascript,Vue.js,Es6 Promise,我试图探索ES6的承诺,不仅仅是从howto文章中获得简单的示例代码,而是实际尝试将学到的概念实现到代码中,以某种方式在实际项目中有用 下面,我在frontend Vue.js/axios中创建了代码,它成功地使用Promises将数据加载到屏幕的五个区域。在我的后端loadData操作中,我让它人工等待一秒钟,这样我就可以看到屏幕的五个区域中的每一个都以1秒的间隔加载数据: <div id="app" class="pageContent"> <div>Data

我试图探索ES6的承诺,不仅仅是从howto文章中获得简单的示例代码,而是实际尝试将学到的概念实现到代码中,以某种方式在实际项目中有用

下面,我在frontend Vue.js/axios中创建了代码,它成功地使用Promises将数据加载到屏幕的五个区域。在我的后端
loadData
操作中,我让它人工等待一秒钟,这样我就可以看到屏幕的五个区域中的每一个都以1秒的间隔加载数据:

<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();

数据1:{{data1}}
数据2:{{data2}}
数据3:{{data3}}
数据4:{{data4}}
数据5:{{data5}}
const app=新的Vue({
el:“#应用程序”,
数据:{
数据1:'正在加载…',
数据2:'正在加载…',
数据3:'正在加载…',
数据4:'正在加载…',
数据5:'正在加载…'
},
方法:{
初始化:函数(){
常数=this;
this.loadData('data1'))
.然后(()=>{
返回.loadData('data2');
})
.然后(()=>{
返回.loadData('data3');
})
.然后(()=>{
返回.loadData('data4');
})
.然后(()=>{
返回.loadData('data5');
});
},
loadData:函数(idCode){
返回新承诺((解决、拒绝)=>{
常数=this;
axios({
方法:“post”,
url:“ControllerShowCaseLoadDataWithPromissions”,
数据:{
操作:“loadData”,
idCode:idCode
}
}).then(函数(响应对象){
const response=qsys.getResponse(responseObject);
[idCode]=response.data.message;
设置超时(解析);
});
});
},
}
});
app.initialize();

虽然这似乎很好,但有人能解释为什么我必须使用
setTimeout(resolve)
(没有它,代码只执行一次)以及这里到底发生了什么吗?我知道这是执行回调的基本方法,就像我们在承诺之前做的那样,但是什么是更干净、更标准的方法呢?

现在做的“更干净”的方法是将所有承诺添加到数组中,并使用
承诺。所有
:

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
函数只执行一次的原因正是因为您没有解析承诺<代码>则
永远不会在链中执行

无需在
setTimeout
中包装
resolve

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

您不必使用
设置超时
,但必须调用
解析
(或
拒绝
)来解决承诺

这到底是怎么回事

您正在执行一系列异步调用,等待前一个调用完成后再执行下一个调用,因为您将承诺链接在一起的方式。这就是为什么如果您不解析第一个操作,其他操作都不会运行:您已经链接了您的操作,因此在每种情况下,只有在上一个操作成功完成时,下一个操作才会运行。如果您不调用
resolve
,尽管操作已完成,但您永远不会解决您创建的承诺,让代码使用该承诺完成操作

我知道这是执行回调的基本方法,就像我们在承诺之前所做的那样,但是什么是更干净、更标准的方法呢

如果必须显式创建承诺,则调用
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;
    });
},
请注意,它返回调用
的结果,然后从
axios
对promise进行调用。(还请注意,由于您使用的是箭头函数,因此不需要=此
对象的
。箭头函数将关闭

如果您希望一个接一个地完成操作,那么您的承诺链就是如何做到这一点的,尽管如果您愿意,您可以更简洁地编写它,并且您应该处理错误(同样,不需要
that=this
):

如果您希望这五个操作并行(重叠)完成,可以立即启动它们并使用
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
函数和
wait

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

setTimeout(resolve)
之前,有哪些替代方法可以让它工作?使用一个虚拟的axios,我看不出立即调用
resolve
有任何问题-所有div都会按顺序填充,无论我是使用
resolve()
还是
setTimeout(resolve)
?除非您的备选方案根本不调用
resolve
,在这种情况下问题很明显,否则在使用Promise构造函数进行其构造的Promise to resolve时,您必须调用
resolve
,否则它将永远挂起这里的两个坏习惯:
axios
返回一个
Promise
,而您正在用自己的
Promise
包装
承诺,没有任何好的理由。使用
函数
而不是
箭头函数
会使y
loadData: async function(idCode) {
    const responseObject = await axios({
        method: 'post',
        url: 'controllerShowcaseLoadDataWithPromises',
        data: {
            action: 'loadData',
            idCode: idCode
        }
    });
    const response = qsys.getResponse(responseObject);
    this[idCode] = response.data.message;
},