【问题标题】:Javascript - Running variables through switch statement in orderJavascript - 按顺序通过 switch 语句运行变量
【发布时间】:2017-10-06 19:41:33
【问题描述】:

我正在尝试让某些 api 调用以正确的顺序运行。用户选择他们选择运行的月份(例如 10 月、11 月、12 月)。我正试图让他们按顺序开火。十月、十一月、十二月(不是十二月、十月、十一月)

第一个函数是一个 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)
                                        })
                                    })
                                })
                            })
                        })
                    })
     },

【问题讨论】:

  • 由于您预期目标的异步性质,我建议利用回调的类和 donecompleted 方法。

标签: javascript loops switch-statement vuejs2


【解决方案1】:

方法 1:链接 Promise

问题的核心是如何确保数据以正确的顺序呈现,因此实现它的一种方法是链接承诺并确保它们以正确的顺序解决。

演示:forEach

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) })
})

演示:减少

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

Vue 演示:

你可以试试这个代码sn-p,或者看看这个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())
       }
     }
  }
})
#app {
  display: flex;
  flex-flow: row nowrap;
  justify-content: space-around;
}
<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>

方法二:RxJS(可观察)

如您所见,虽然 promise 很棒,但链接 promise 有时仍然很困难。如果您之前使用过 Angular 2,那么您之前就听说过 Observables。因此,每当我需要链接 Promise 时,我都会使用 RxJS,我将 Promise 视为 'stream' 并将它们完全concat(如果我不关心顺序,我可以使用 merge ),更容易处理错误,并提供更好的代码可读性。你可以在link 了解更多关于 RxJS 和 Observables 的信息。另外,请注意 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)
)
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.4.3/Rx.js"&gt;&lt;/script&gt;

Vue 演示:

你可以试试这个代码sn-p,或者看看这个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!')
         )
       }
     }
  }
})
#app {
  display: flex;
  flex-flow: row nowrap;
  justify-content: space-around;
}
<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>

【讨论】:

    【解决方案2】:

    您可能想查看 Promise: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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-17
      • 1970-01-01
      • 2022-01-12
      • 1970-01-01
      • 2020-06-28
      • 2023-04-04
      • 2020-12-05
      相关资源
      最近更新 更多