使用setTimeout以及async await的誤區

咱們平時在遇到不少比較怪異的事情的時候,咱們會使用setTimeout這樣的奇淫異技,好比避免執行的太快了,某些數據尚未來等,我以前基本不用這個,可是在最近的一個項目中用到了。 項目大體是這樣的,用的element-ui的el-upload來實現圖片上傳,就是一個彈框,裏面有不少tab頁,每一個tab也都有el-upload,只是能每一個上傳的參數和地址什麼的是不一樣的。javascript

<div>操做類型</div>
<el-radio
	v-model="currentSelect"
	v-for="(item, index) in configs"
	:label="index"
	:key="'operateRadio' + index"
	>{{ item.label }}
</el-radio>
<el-upload :data="data" :action="url" :auto-upload="false" ref="elUpload">
	<el-button type="primary" size="small" @click="submit">上傳文件</el-button>
</el-upload>
	
props:[''configs"]
data(){
	data: "",
	url: "",
	currentSelect: 0,
},
computed: {
	config() {
	   return this.configs[this.currentSelect] || {};
	},
},
methods: {
	submit(){
	    this.data = this.config.data;
		this.url = this.config.url;
		console.log(this.data, this.url);
		this.$refs.elUpload.submit();
	}
}

複製代碼

當時的問題是,每次在用戶點擊切換了操做模式後點擊上傳沒有問題,若是不點的話用(默認的第一種)通常也沒有問題,只是偶爾會出現傳遞給el-upload的data參數再上傳時沒有傳遞給action的接口地址的狀況, 可是在用在調用this.$refs.elUpload.submit();上傳以前打印console.log(this.data, this.url);確實值已經打印了,他們的指都是字符串,不存在console打印「不許」的狀況。最後解決這個辦法就是用了setTimeouthtml

this.data = this.config.data;
this.url = this.config.url;
setTimeout(() => { 
	this.$refs.elUpload.submit();
}, 200);
複製代碼

感受多是el-upload監聽prop的變化不及時,或者watch時沒有用相似immediate: true,之類的吧。前端

如今你們通常都知道一些事件隊列的知識,好比setTimeout是屬於宏隊列,Promise是微隊列。週五就看到有同事寫了相似這樣的代碼:java

const arr = []
list.forEach(async item => {
  const res = await axios.post(item.url);
  arr.push(res.data.time);
})
setTimeout(() => {
	console.log('arr ', arr);
}, 1000);
複製代碼

而後在arr裏面有時取不到值跑過來問我,我問他爲何這麼寫,而後他就給我說了宏隊列、微隊列那一套,還跟我說什麼用async await把異步變成同步了。。。ios

而後我讓他用Promise.all來寫express

const arr = await Promise.all(list.map(item => axios.post(item.url))).map(item => item.data.time);
console.log('arr ', arr);
複製代碼

這樣確定沒問題的。element-ui

我順便寫了個demo讓他完全明白,本身的那種setTimeout騷操做是多麼的不靠譜 先用express寫個後端接口axios

// server.js
const app = require('express')();
app.post('*', (req, res, next) => {
  setTimeout(() => {
    res.send({
      post: Date.now()
    });
  }, 4000)
});
app.listen(3000);
複製代碼

客戶端代碼以下:後端

// client.js
const result = [];
list.forEach(async item => {
  const res = await axios.post('http://localhost:3000/post');
  result.push(res.data.time);
})
setTimeout(() => {
  console.log('執行settimeout', result);
}, 600);
console.log('同步', result);
複製代碼

執行結果以下bash

同步 []
執行settimeout []
接口數據 1551629543195
接口數據 1551629543195
複製代碼

細心的讀者可能看到上面兩個setTimeout的時間了,後端接口是4000毫秒,前端這邊是600毫秒,這種狀況下,前端的setTimeout是百分之百拿不到數據的,若是前端把600改爲6000就能夠拿到了。

同步 []
接口數據 1551629811109
接口數據 1551629811111
執行settimeout [ 1551629811109, 1551629811111 ]
複製代碼

可是實際狀況能這樣用嗎?確定不行,你怎麼知道接口大概多久能返回接口,這不是胡鬧嗎?

寫累了,開始總結吧。 首先是在同一個事件循環裏面微隊列永遠在宏隊列前面執行,async await只是把異步的行爲用同步的寫法寫出來,而非是把異步變成同步,這樣更符合咱們的同步思惟罷了。

原文地址:使用setTimeout以及async await的誤區

相關文章
相關標籤/搜索