我正在尝试以正确的顺序运行某些api调用。用户选择他们选择运行的月份(例如10月,11月,12月)。我试图让它们按顺序点火。 10月,11月,12月(不是12月,10月,11月)
第一个函数是一个If语句,如果整个数组都存在,我可以让它按顺序运行,当它们开始调整它时我不能保持顺序。
因此getStationsInOrder可以正常使用回调 - 但我似乎无法通过正确的顺序将循环发送到交换机。我已经从交换机中删除了返回,因此它不会以数组中的第一个月结束
例子。用户仅选择11月,12月,1月 - 按顺序触发这些api调用。数月传递给for循环,然后循环将其传递给开关。
感谢您提供的任何帮助。
noaaData: function () {
console.log(this.checkedMonths, 'Months Selected')
//if all checked get all data, array smaller than 7 get
selected stations
if (!this.checkedMonths || this.checkedMonths.length == 7){
//trigger this function - runs api.get's in order
this.getStationsInOrder(this.userFIPS, function(){
console.log('Done here move on')
})
} else {
//this does NOT run in order - there by messing up all other equations
this.getStationsChecked(this.userFIPS)
}//end else
},
getStationsChecked: function (userFIPS){
for (var i = 0; i < this.checkedMonths.length; i++) {
console.log(this.checkedMonths[i], 'month in ooop')
switch (this.checkedMonths[i]) {
case 'October':
this.getStationsOct(userFIPS)
break;
case 'November':
this.getStationsNov(userFIPS)
console.log('nov')
break;
case 'December':
this.getStationsDec(userFIPS)
console.log('dec')
break;
case 'January':
this.getStationsJan(userFIPS)
console.log('jan')
break;
case 'February':
this.getStationsFeb(userFIPS)
console.log('feb')
break;
case 'March':
this.getStationsMar(userFIPS)
console.log('mar')
break;
case 'April':
this.getStationsApr(userFIPS)
console.log('apr')
break;
default: 'Error getStationsChecked default case'
}
}
},
getStationsInOrder: function(userFIPS, callback){
self = this
// series of callbacks to run each in order - oct thru
// April - triggered in if statement in noaaData()
self.getStationsOct(userFIPS, function(){
self.getStationsNov(userFIPS, function(){
self.getStationsDec(userFIPS, function(){
self.getStationsJan(userFIPS, function(){
self.getStationsFeb(userFIPS, function (){
self.getStationsMar(userFIPS, function(){
self.getStationsApr(userFIPS, callback)
})
})
})
})
})
})
},
答案 0 :(得分:0)
您可能希望查看承诺:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises
一个简单的例子:
let callNumber = 0;
let timeoutSpeed = 5000;
function AsyncMocker(resolve)
{
callNumber = ++callNumber;
timeoutSpeed -= 500;
return new Promise(function(resolve)
{
// simulate asynchronous behaviour.
setTimeout(function()
{
console.log('Async task has been completed from call number: ' + callNumber);
// tell the promise that the async work is done.
resolve();
}, timeoutSpeed);
});
}
AsyncMocker().then(AsyncMocker)
.then(AsyncMocker)
.then(AsyncMocker)
.then(AsyncMocker)
.then(AsyncMocker)
.then(AsyncMocker)
.then(AsyncMocker);
答案 1 :(得分:0)
问题的核心是如何确保数据以正确的顺序呈现,因此实现它的一种方法是通过链接承诺并确保它们以正确的顺序解决。
const numbers = [1,2,3,4,5,6,7,8,9,10]
const createPromise = (number) => {
const url = 'https://jsonplaceholder.typicode.com/posts/' + number
return () => fetch(url)
}
const promises = numbers.map((number) => createPromise(number))
let dummyPromise = Promise.resolve();
promises.forEach((promise) => {
dummyPromise = dummyPromise
.then(() => promise())
.then((res) => res.json())
.then((result) => { console.log(result) })
})
&#13;
const numbers = [1,2,3,4,5,6,7,8,9,10]
const createPromise = (number) => {
const url = 'https://jsonplaceholder.typicode.com/posts/' + number
return () => fetch(url)
}
const promises = numbers.map((number) => createPromise(number))
promises.reduce((acc, promise) => acc
.then(() => promise())
.then((res) => res.json())
.then((result) => { console.log(result) })
, Promise.resolve())
&#13;
您可以尝试使用此代码段,或查看此codepen,您可以参考id
来比较数据的顺序:
const app = new Vue({
el: '#app',
data: {
months: { Jan: 1, Feb: 2, Mar: 3, Apr: 4, May: 5, Jun: 6, Jul: 7, Aug: 8, Sep: 9, Oct: 10, Nov: 11, Dec: 12},
availableMonths: [
{ month: 'Jan', selected: false }, { month: 'Feb', selected: false }, { month: 'Mar', selected: false },
{ month: 'Apr', selected: false }, { month: 'May', selected: false }, { month: 'Jun', selected: false },
{ month: 'Jul', selected: false }, { month: 'Aug', selected: false }, { month: 'Sep', selected: false },
{ month: 'Oct', selected: false }, { month: 'Nov', selected: false }, { month: 'Dec', selected: false },
],
retrievedData: []
},
methods: {
// helper method for constructing API url
getMonthNumber(month) { return this.months[month] },
// this method returns a function that will return a promise for fetching data
getFromApiByMonth(month) {
const url = 'https://jsonplaceholder.typicode.com/posts/' + this.getMonthNumber(month)
return () => fetch(url)
},
// method for getting all the data
getAllData() {
// making sure data will be retrieved in order
this.retrievedData = []
const promises = this.availableMonths
.filter((item) => item.selected)
.map((item) => this.getFromApiByMonth(item.month))
if (promises.length > 0) {
// let dummyPromise = Promise.resolve();
// promises.forEach((promise) => {
// dummyPromise = dummyPromise
// .then(() => promise())
// .then((res) => res.json())
// .then((result) => { this.retrievedData.push(result) })
// })
promises.reduce((acc, promise) => acc
.then(() => promise())
.then((res) => res.json())
.then((result) => { this.retrievedData.push(result) })
, Promise.resolve())
}
}
}
})
&#13;
#app {
display: flex;
flex-flow: row nowrap;
justify-content: space-around;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<div id="app">
<div>
<button v-on:click="getAllData()">Get Data</button>
<div v-for="item in availableMonths">
{{item.month}}<input v-model="item.selected" type="checkbox" v-model="toggle">
</div>
</div>
<div>
<ul v-for="data in retrievedData">
<li>{{data}}</li>
</ul>
</div>
</div>
&#13;
正如你所看到的那样,承诺虽然很棒,但链接承诺有时仍然很难。如果您之前使用过Angular 2,那么之前您已经听说过Observables。因此,每当我需要链接承诺时,我都会使用RxJS,我将承诺视为&#39; stream&#39;和 concat 完全相同(如果我不关心订单,我可以使用合并),它更容易进行错误处理并迎合更好的代码可读性。您可以了解有关RxJS和Observables link的更多信息。另请注意,Observable将包含在ES8中。
let retrievedData = []
const numbers = [1,2,3,4,5,6,7,8,9,10]
const streams = numbers
.map((number) => 'https://jsonplaceholder.typicode.com/posts/'+number)
.map((url) => Rx.Observable.fromPromise(
fetch(url).then((res) => res.json())
))
// every promise now becomes a stream
// concat all the streams together
const stream = Rx.Observable.concat(...streams)
// subscribe is like start watching a YouTube video,
// which keeps emitting values until the stream is complete
stream.subscribe(
// for every result emitted from stream
(result) => retrievedData.push(result),
// error handling
(err) => console.log(err),
// when the stream is complete
() => console.log(retrievedData)
)
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.4.3/Rx.js"></script>
&#13;
您可以尝试使用此代码段,或查看此codepen:
const app = new Vue({
el: '#app',
data: {
months: { Jan: 1, Feb: 2, Mar: 3, Apr: 4, May: 5, Jun: 6, Jul: 7, Aug: 8, Sep: 9, Oct: 10, Nov: 11, Dec: 12},
availableMonths: [
{ month: 'Jan', selected: false }, { month: 'Feb', selected: false }, { month: 'Mar', selected: false },
{ month: 'Apr', selected: false }, { month: 'May', selected: false }, { month: 'Jun', selected: false },
{ month: 'Jul', selected: false }, { month: 'Aug', selected: false }, { month: 'Sep', selected: false },
{ month: 'Oct', selected: false }, { month: 'Nov', selected: false }, { month: 'Dec', selected: false },
],
retrievedData: []
},
methods: {
// helper method for constructing API url
getMonthNumber(month) { return this.months[month] },
// this method returns a function that will return a promise for fetching data
getFromApiByMonth(month) {
const url = 'https://jsonplaceholder.typicode.com/posts/' + this.getMonthNumber(month)
return Rx.Observable.fromPromise(
fetch(url).then((res) => res.json())
)
},
// method for getting all the data
getAllData() {
// making sure data will be retrieved in order
this.retrievedData = []
const streams = this.availableMonths
.filter((item) => item.selected)
.map((item) => this.getFromApiByMonth(item.month))
if (streams.length > 0) {
const stream = Rx.Observable.concat(...streams)
stream.subscribe(
(result) => this.retrievedData.push(result),
err => console.log(err),
() => console.log('Fetching Complete!')
)
}
}
}
})
&#13;
#app {
display: flex;
flex-flow: row nowrap;
justify-content: space-around;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.4.3/Rx.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<div id="app">
<div>
<button v-on:click="getAllData()">Get Data</button>
<div v-for="item in availableMonths">
{{item.month}}<input v-model="item.selected" type="checkbox" v-model="toggle">
</div>
</div>
<div>
<ul v-for="data in retrievedData">
<li>{{data}}</li>
</ul>
</div>
</div>
&#13;