最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

實(shí)例詳解JS中的事件循環(huán)機(jī)制

 更新時(shí)間:2022年04月21日 10:09:36   作者:添財(cái)青年  
JavaScript是單線程的腳本語言,所以代碼在執(zhí)行的時(shí)候,只有一個(gè)主線程來執(zhí)行所有的任務(wù),同一個(gè)時(shí)間只能做同一件事情。本文就為大家詳細(xì)講解一下它的件循環(huán)機(jī)制,需要的可以參考一下

一、前言

之前我們把react相關(guān)鉤子函數(shù)大致介紹了一遍,這一系列完結(jié)之后我莫名感到空虛,不知道接下來應(yīng)該更新有關(guān)哪方面的文章。最近想了想,打算先回歸一遍JS基礎(chǔ),把一些比較重要的基礎(chǔ)知識點(diǎn)回顧一下,然后繼續(xù)擼框架(可能是源碼、也可能補(bǔ)全下全家桶)。不積跬步無以至千里,萬丈高樓咱們先從JS的事件循環(huán)機(jī)制開始吧,廢話不多說,開搞開搞!

在JS中,我們所有的任務(wù)可以分為同步任務(wù)和異步任務(wù)。那么什么是同步任務(wù)?什么又是異步任務(wù)呢?

同步任務(wù):是在主線程執(zhí)行棧上排隊(duì)執(zhí)行的任務(wù),只有前一個(gè)任務(wù)執(zhí)行完畢,才能執(zhí)行后一個(gè)任務(wù);比如:console.log、賦值語句等。

異步任務(wù):不進(jìn)入主線程,是進(jìn)入任務(wù)隊(duì)列的任務(wù),只有等主線程任務(wù)執(zhí)行完畢,"任務(wù)隊(duì)列"開始通知主線程,請求執(zhí)行任務(wù),該任務(wù)才會(huì)進(jìn)入主線程執(zhí)行。比如:ajax網(wǎng)絡(luò)請求,setTimeout 定時(shí)函數(shù)等都屬于異步任務(wù),異步任務(wù)會(huì)通過任務(wù)隊(duì)列的機(jī)制(先進(jìn)先出的機(jī)制)來進(jìn)行協(xié)調(diào)。

我們執(zhí)行一段代碼時(shí),在我們主線程的執(zhí)行棧執(zhí)行過程中,如果遇到同步任務(wù)會(huì)立即執(zhí)行,如果遇到異步任務(wù)會(huì)暫時(shí)掛起,將此異步任務(wù)推入任務(wù)隊(duì)列中(隊(duì)列的執(zhí)行機(jī)制遵循先進(jìn)先出)。當(dāng)主線程執(zhí)行棧里的同步任務(wù)執(zhí)行完畢后,js執(zhí)行引擎會(huì)去任務(wù)隊(duì)列中讀取掛起的異步任務(wù)并將其推入到執(zhí)行棧中執(zhí)行。這個(gè)不斷重復(fù)的過程(執(zhí)行棧執(zhí)行--->判斷同異步--->同步執(zhí)行/異步掛起推入事件對列--->??蘸笕∈录?duì)列里任務(wù)并推入執(zhí)行棧執(zhí)行--->繼續(xù)判斷同異步--->.......)就是本文所要介紹的事件循環(huán)。

二、宏、微任務(wù)

我們每進(jìn)行一次事件循環(huán)的操作被稱之為tick,在介紹一次 tick 的執(zhí)行步驟之前,我們需要補(bǔ)充兩個(gè)概念:宏任務(wù)、微任務(wù)。

宏任務(wù)和微任務(wù)嚴(yán)格來說是ES6之后才有的概念(原因在于ES6提出了Promise這個(gè)概念);在Es6之后我們把JS的任務(wù)更細(xì)分成了宏任務(wù)和微任務(wù)。

其中,宏任務(wù)主要包括:script(整體代碼)、setTimeout、setInterval、I/O、UI交互事件、postMessage、requestAnimationFrame(幀動(dòng)畫)、MessageChannel、setImmediate(Node.js環(huán)境);

微任務(wù)主要包括:Promise.then、MutaionObserver、process.nextTick(Node.js環(huán)境);

好了,了解了宏微任務(wù)的概念之后我們就來掰扯掰扯每次tick的執(zhí)行順序吧。首先看下圖:

三、Tick 執(zhí)行順序

1、首先執(zhí)行一個(gè)宏任務(wù)(棧中沒有就從事件隊(duì)列中獲?。?;

2、執(zhí)行過程中如果遇到微任務(wù),就將它添加到微任務(wù)的任務(wù)隊(duì)列中、如果有宏任務(wù)的話推到相應(yīng)的事件隊(duì)列中去;

3、宏任務(wù)執(zhí)行完畢后,立即執(zhí)行當(dāng)前微任務(wù)隊(duì)列中的所有微任務(wù)(依次執(zhí)行);

4、當(dāng)前宏任務(wù)執(zhí)行完畢,開始進(jìn)行渲染;5、開始下一個(gè)宏任務(wù)(從事件隊(duì)列中獲?。╅_啟下一次的tick;

需要注意的是:宏任務(wù)執(zhí)行過程中如果宏任務(wù)中又添加了一個(gè)新的宏任務(wù)到任務(wù)隊(duì)列中。 這個(gè)新的宏任務(wù)會(huì)等到下一次事件循環(huán)再執(zhí)行;而微任務(wù)則不同,微任務(wù)執(zhí)行過程中如果又添加了新的微任務(wù),則新的微任務(wù)也會(huì)在本次微任務(wù)執(zhí)行過程中被執(zhí)行,直到微任務(wù)隊(duì)列為空。每次宏任務(wù)執(zhí)行完在開啟下一次宏任務(wù)時(shí)會(huì)把微任務(wù)隊(duì)列中所有的微任務(wù)執(zhí)行完畢!

四、案例詳解

概念性的東西說完了,下面就來找些demo練練手吧!

1.摻雜setTimeout

console.log('開始');

setTimeout(()=>{
    console.log('同級的定時(shí)器');
      setTimeout(() => {
          console.log('內(nèi)層的定時(shí)器');
      }, 0);
},0)

console.log('結(jié)束');

輸出結(jié)果為

開始 -> 結(jié)束 -> 同級的定時(shí)器 ->內(nèi)層的定時(shí)器

解釋上述代碼:

  • 整體代碼作為一個(gè)宏任務(wù)進(jìn)入主線程執(zhí)行棧中;
  • 遇到console.log('開始'),控制臺輸出 開始;
  • 遇到有一個(gè)宏任務(wù)setTimeout,JS引擎將之掛起,并推入任務(wù)隊(duì)列;
  • 遇到console.log('結(jié)束'),控制臺輸出 結(jié)束;本次宏任務(wù)執(zhí)行完畢,發(fā)現(xiàn)本次并無微任務(wù),GUI進(jìn)行render渲染完畢開啟下一次宏任務(wù)執(zhí)行,本次tick結(jié)束。
  • JS引擎從任務(wù)隊(duì)列拿出第一個(gè)setTimeout宏任務(wù),將至推入主線程執(zhí)行棧, 開始進(jìn)行第二個(gè)宏任務(wù);
  • 執(zhí)行setTimeout回調(diào),遇到 console.log('同級的定時(shí)器'),控制臺輸出 同級的定時(shí)器;
  • 遇到第二個(gè)setTimeout ,這是個(gè)本次宏任務(wù)產(chǎn)生的新的宏任務(wù),將此宏任務(wù)掛起,并推入任務(wù)隊(duì)列;
  • 同樣此時(shí)發(fā)現(xiàn)沒有微任務(wù),則GUI接管開始進(jìn)行渲染,渲染完畢又開啟下一次宏任務(wù),tick結(jié)束;
  • JS引擎又從任務(wù)隊(duì)列拿出第二個(gè)setTimeout宏任務(wù),將之推入主線程執(zhí)行棧, 開始進(jìn)行第三個(gè)宏任務(wù);
  • 執(zhí)行第二個(gè)setTimeout回調(diào),遇到 console.log('內(nèi)層的定時(shí)器'),控制臺輸出 內(nèi)層的定時(shí)器;
  • 本次宏任務(wù)執(zhí)行完畢發(fā)現(xiàn)沒有微任務(wù),結(jié)束。

2.摻雜微任務(wù),此處主要是Promise.then

console.log('script start');

setTimeout(function() {
  new Promise(resolve=>{
        console.log('000');
      resolve()
    }).then(res=>{
        console.log('這是微任務(wù)');
    })
  console.log('timeout1');
}, 10);

new Promise(resolve => {
    console.log('promise1');       
    resolve();
    setTimeout(() => console.log('timeout2'), 10);
}).then(function() {
    console.log('then1')
})

console.log('script end');

輸出結(jié)果為:

script start -> promise1 -> script end -> then1 -> 000 -> timeout1 -> 這是微任務(wù) -> timeout2

解釋上述代碼:

  • 整體script作為一個(gè)宏任務(wù)進(jìn)入主線程執(zhí)行棧;
  • 遇到 console.log('script start') 輸出 script start ;
  • 遇到setTimeout作為新的一個(gè)宏任務(wù)連同其回調(diào)內(nèi)容一同推入任務(wù)隊(duì)列 ;
  • 遇到和script start 同級的new Promise 進(jìn)行執(zhí)行,此處需注意:Promise內(nèi)容是同步任務(wù),它的.then才是微任務(wù)會(huì)被推入微任務(wù)隊(duì)列。所有此處JS引擎的處理邏輯是:遇到 console.log('promise1') 輸出 promise1 ,遇到resolve() 會(huì)將 Promise的.then函數(shù)推入微任務(wù)隊(duì)列(注意,我們常說微任務(wù)時(shí)宏任務(wù)的小尾巴,指的是本次宏任務(wù)產(chǎn)生的微任務(wù)都會(huì)在本次宏任務(wù)執(zhí)行完之后進(jìn)行執(zhí)行清空。);遇到resolve下面的setTimeout這是個(gè)新的宏任務(wù),會(huì)被掛起并推入任務(wù)隊(duì)列。
  • 繼續(xù)順序執(zhí)行,執(zhí)行到 console.log('script end') ,輸出script end;此時(shí)第一個(gè)宏任務(wù)執(zhí)行完畢,JS引擎開始清理小尾巴(執(zhí)行并清空微任務(wù)隊(duì)列)。
  • 此時(shí)由本次執(zhí)行宏任務(wù)的過程中產(chǎn)生了 .then(function() { console.log('then1')}) 這個(gè)微任務(wù),JS引擎會(huì)將此任務(wù)內(nèi)的回調(diào)推入執(zhí)行棧進(jìn)行執(zhí)行,輸出 then1;
  • 微任務(wù)隊(duì)列為空,開啟下一個(gè)宏任務(wù),第一輪tick結(jié)束;
  • JS引擎從任務(wù)隊(duì)列中拿script start下面那個(gè)setTimeout宏任務(wù)將回調(diào)推入主線程執(zhí)行棧中進(jìn)行執(zhí)行;
  • 遇到了Promise,執(zhí)行其內(nèi)容:遇到 console.log('000') 輸出 000;
  • 執(zhí)行 resolve() 將.then函數(shù)推入微任務(wù)隊(duì)列(是此次宏任務(wù)的小尾巴);
  • 繼續(xù)執(zhí)行,遇到 console.log('timeout1') 輸出 timeout1;本次宏任務(wù)執(zhí)行完畢;
  • 宏任務(wù)執(zhí)行完畢后緊接著處理小尾巴: .then(res=>{ console.log('這是微任務(wù)'); }) 輸出 這是微任務(wù);
  • 微任務(wù)隊(duì)列清空后,繼續(xù)開啟下一個(gè)宏任務(wù),第二輪tick結(jié)束;
  • 將任務(wù)隊(duì)列中的 setTimeout(() => console.log('timeout2'), 10); 回調(diào)推入執(zhí)行棧中執(zhí)行,輸出 timeout2 ; 無微任務(wù),第三輪tick結(jié)束,任務(wù)隊(duì)列也為空。

好了,相信經(jīng)過這兩個(gè)例子,小伙伴們對事件循環(huán)有了初步的認(rèn)識。接下來我們再頑皮一下:對上面這個(gè)demo做一丟丟微調(diào)

微調(diào)一 : 其他地方不變,then里塞定時(shí)器

setTimeout(function() {
  new Promise(resolve=>{
        console.log('000');
      resolve()
    }).then(res=>{
         setTimeout(()=>{
         console.log('這次的執(zhí)行順序呢?') -----> 如果這里再塞個(gè)定時(shí)器呢?執(zhí)行順序是什么?
        },10)
        console.log('這是微任務(wù)');
    })
  console.log('timeout1');
}, 10);

微調(diào)二:其他地方不變,對Promise進(jìn)行鏈?zhǔn)秸{(diào)用

new Promise(resolve => {
    console.log('promise1');       
    resolve();
    setTimeout(() => console.log('timeout2'), 10);
}).then(function() {
    console.log('then1')
}).then(()=>{
    console.log('then2')
}).then(()=>{
    console.log('then3')
})

此Promise進(jìn)行鏈?zhǔn)秸{(diào)用,其他地方不動(dòng),此時(shí)的執(zhí)行順序是什么?

提示:在一次tick結(jié)束時(shí),此tick內(nèi)微任務(wù)隊(duì)列中的微任務(wù)一定會(huì)執(zhí)行完并清空,如果在執(zhí)行過程中又產(chǎn)生了微任務(wù),那么同樣會(huì)在此tick過程中執(zhí)行完畢;而宏任務(wù)的執(zhí)行則可以看成是下一次tick的開始。

3.摻雜async/await

在進(jìn)行demo解析之前,我們需要補(bǔ)充一下async/await的相關(guān)知識點(diǎn)。

async

async相當(dāng)于隱式返回Promise:當(dāng)我們在函數(shù)前使用async的時(shí)候,使得該函數(shù)返回的是一個(gè)Promise對象,async的函數(shù)會(huì)在這里幫我們隱式使用Promise.resolve();

下面看個(gè)小demo來理解下async函數(shù)是怎么隱式轉(zhuǎn)換的:

async function test() {
    console.log('這是async函數(shù)')
    return '測試隱式轉(zhuǎn)換' 
}

上面這個(gè)async就相當(dāng)于如下代碼:

function test(){
    return new Promise(function(resolve) {
      console.log('這是async函數(shù)')
       resolve('測試隱式轉(zhuǎn)換')
   })
}

await

await表示等待,是右側(cè)表達(dá)式的結(jié)果,這個(gè)表達(dá)式的計(jì)算結(jié)果可以是 Promise 對象的值或者一個(gè)函數(shù)的值(換句話說,就是沒有特殊限定)。并且await只能在帶有async的內(nèi)部使用;使用await時(shí),會(huì)從右往左執(zhí)行,當(dāng)遇到await時(shí),會(huì)阻塞函數(shù)內(nèi)部處于它后面的代碼,去執(zhí)行該函數(shù)外部的 代碼 , 當(dāng)外部代碼執(zhí)行完畢,再回到該函數(shù)內(nèi)部執(zhí)行await后面剩余的代碼;

好了,補(bǔ)充完前置知識我們來做個(gè)demo助助興:

摻雜async/await的事件循環(huán)

async function async2() {				
    console.log('async2');     
}

async function async1() {
    console.log('async1 start');
    await async2();
    console.log('async1 end');
}

console.log('script start');

setTimeout(function () {
    console.log('setTimeout');
}, 0);

async1();

new Promise((resolve) => {
    resolve()
    console.log('promise1');
}).then(function () {
    console.log('promise2');
});

console.log('script end');

輸出順序?yàn)?/p>

script start --> async1 start --> async2 --> promise1 --> script end --> async1 end --> promise2 --> setTimeout  

首先為方便理解我們先將async函數(shù)轉(zhuǎn)為return Promise的那種形式:

①:
async function async2() {				
    console.log('async2');     
}
轉(zhuǎn)換后如下:
function async2() {			
    return  new Promise(resolve=>{
       console.log('async2');     
    })
}


②:
async function async1() {
    console.log('async1 start');
    await async2();
    console.log('async1 end');
}
轉(zhuǎn)換后如下:
function async1() {
  return new Promise(resolve=>{
    console.log('async1 start');
    #執(zhí)行async2,并且會(huì)阻塞其后面的代碼
    console.log('async1 end');
  })
}

所以,最后我們包含async函數(shù)的代碼塊就相當(dāng)于如下代碼:

function async2() {			
    return  new Promise(resolve=>{
       console.log('async2');     
    })
}

function async1() {
  return new Promise(resolve=>{
    console.log('async1 start');
    #執(zhí)行async2,并且會(huì)阻塞其后面的代碼,在此處是阻塞了console.log('async1 end')的執(zhí)行
    console.log('async1 end');
  })
}
=============上面為聲明部分===========
console.log('script start');

setTimeout(function () {
    console.log('setTimeout');
}, 0);

new Promise(resolve=>{
    console.log('async1 start');
    #執(zhí)行async2,并且會(huì)阻塞其后面的代碼,在此處是阻塞了console.log(async1end)的執(zhí)行;這里相當(dāng)于awaitasync2()
   
    console.log('async1 end');
  })
}

new Promise((resolve) => {
    resolve()
    console.log('promise1');
}).then(function () {
    console.log('promise2');
});

console.log('script end');

經(jīng)過一系列騷操作之后,我們終于可以來分析這個(gè)代碼塊的執(zhí)行順序了,廢話不多說,開沖。

解釋上述代碼:

  • 首先整體代碼作為第一個(gè)宏任務(wù)進(jìn)入主線程執(zhí)行棧;
  • 首先順序執(zhí)行,遇到了async2、async1 函數(shù)的聲明,不進(jìn)行任何輸出;
  • 執(zhí)行到console.log('script start') 輸出 script start ;
  • 繼續(xù)執(zhí)行,遇到setTimeout宏任務(wù),掛起并推入任務(wù)隊(duì)列;
  • 接著執(zhí)行Promise內(nèi)容部分,遇到console.log('async1 start'),輸出async1 start ;
  • 這一步重點(diǎn)來了,遇到了await,這該怎么辦呢?別急,咱們再來看看使用await會(huì)發(fā)生什么:使用await時(shí),會(huì)從右往左執(zhí)行,當(dāng)遇到await時(shí),會(huì)阻塞函數(shù)內(nèi)部處于它后面的代碼,去執(zhí)行該函數(shù)外部的 代碼 , 當(dāng)外部代碼執(zhí)行完畢,再回到該函數(shù)內(nèi)部執(zhí)行await后面剩余的代碼;
  • 好了,下面開始解釋await async2():由于是是從右往左執(zhí)行,所以我們首先執(zhí)行了async2()輸出了一個(gè)Promise,我們執(zhí)行了Promise的內(nèi)容輸出了async2;async2執(zhí)行完了之后,遇到await,完全不出意外,后面的代碼被阻塞;我們?nèi)?zhí)行外面的代碼;
  • 因?yàn)閏onsole.log('async1 end')被await阻塞掉了,我們先執(zhí)行外面的代碼:執(zhí)行了外面Promise的內(nèi)容,遇到了resolve(),將.then函數(shù)推入微任務(wù)隊(duì)列;然后執(zhí)行console.log('promise1'),輸出 promise1;
  • 最后執(zhí)行到console.log('script end'),輸出 script end;
  • 到此,我們外層的代碼就執(zhí)行完畢,現(xiàn)在想想好像少了什么?往前一看,我們console.log('async1 end')還在等待,此時(shí),JS引擎執(zhí)行l(wèi)og輸出 async1 end 。
  • 由此,我們本次的宏任務(wù)就執(zhí)行完畢,下面看看是否有微任務(wù),JS引擎去微任務(wù)隊(duì)列一看,好家伙,還藏著一個(gè) then(function () {console.log('promise2');}); 把此任務(wù)回調(diào)推到執(zhí)行棧中執(zhí)行,輸出 promise2;
  • 此次tick執(zhí)行結(jié)束,開啟下一個(gè)宏任務(wù);
  • 從任務(wù)隊(duì)列拿setTimeout這個(gè)宏任務(wù),塞入執(zhí)行棧執(zhí)行,打印輸出setTimeout,本次無微任務(wù),結(jié)束tick;
  • 循環(huán)結(jié)束;

到此這篇關(guān)于實(shí)例詳解JS中的事件循環(huán)機(jī)制的文章就介紹到這了,更多相關(guān)JS事件循環(huán)機(jī)制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • javascript實(shí)現(xiàn)模擬時(shí)鐘的方法

    javascript實(shí)現(xiàn)模擬時(shí)鐘的方法

    這篇文章主要介紹了javascript實(shí)現(xiàn)模擬時(shí)鐘的方法,涉及javascript操作時(shí)間實(shí)時(shí)顯示的相關(guān)技巧,需要的朋友可以參考下
    2015-05-05
  • js實(shí)現(xiàn)3D照片墻效果

    js實(shí)現(xiàn)3D照片墻效果

    這篇文章主要介紹了js實(shí)現(xiàn)3D照片墻效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-10-10
  • js實(shí)現(xiàn)WebSocket 連接的示例代碼

    js實(shí)現(xiàn)WebSocket 連接的示例代碼

    本文主要介紹了js實(shí)現(xiàn)WebSocket 連接的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-05-05
  • javascript中對對層的控制

    javascript中對對層的控制

    javascript中對對層的控制...
    2006-12-12
  • 小程序獲取當(dāng)前位置加搜索附近熱門小區(qū)及商區(qū)的方法

    小程序獲取當(dāng)前位置加搜索附近熱門小區(qū)及商區(qū)的方法

    這篇文章主要介紹了小程序獲取當(dāng)前位置加搜索附近熱門小區(qū)及商區(qū)的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-04-04
  • bootstrap表格分頁實(shí)例講解

    bootstrap表格分頁實(shí)例講解

    這篇文章主要為大家詳細(xì)介紹了bootstrap表格分頁實(shí)例講解,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • JavaScript函數(shù)節(jié)流和函數(shù)防抖之間的區(qū)別

    JavaScript函數(shù)節(jié)流和函數(shù)防抖之間的區(qū)別

    本文主要介紹了JavaScript函數(shù)節(jié)流和函數(shù)防抖之間的區(qū)別。具有很好的參考價(jià)值,下面跟著小編一起來看下吧
    2017-02-02
  • TypeScript學(xué)習(xí)之強(qiáng)制類型的轉(zhuǎn)換

    TypeScript學(xué)習(xí)之強(qiáng)制類型的轉(zhuǎn)換

    眾所周知TypeScript是一種由微軟開發(fā)的自由和開源的編程語言。它是JavaScript的一個(gè)超集,而且本質(zhì)上向這個(gè)語言添加了可選的靜態(tài)類型和基于類的面向?qū)ο缶幊蹋旅孢@篇文章主要介紹了TypeScript中強(qiáng)制類型的轉(zhuǎn)換,需要的朋友可以參考借鑒下。
    2016-12-12
  • 簡單談?wù)刯son跨域

    簡單談?wù)刯son跨域

    本文主要給大家講解了javascript中的json跨域問題,以及跨域安全性的解決辦法,總結(jié)了2點(diǎn),分享給大家,希望大家能夠喜歡。
    2016-03-03
  • js仿小米手機(jī)上下滑動(dòng)效果

    js仿小米手機(jī)上下滑動(dòng)效果

    這篇文章主要為大家詳細(xì)介紹了JavaScript仿小米手機(jī)上下滑動(dòng)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-02-02

最新評論

方山县| 青州市| 旬邑县| 全州县| 新兴县| 伊宁县| 宜春市| 陕西省| 偏关县| 宜州市| 西畴县| 靖江市| 申扎县| 随州市| 龙江县| 绥芬河市| 邵武市| 凤凰县| 宝清县| 全州县| 黄石市| 伊宁县| 临猗县| 阜城县| 沿河| 吕梁市| 景洪市| 沈阳市| 东乌珠穆沁旗| 安岳县| 麻江县| 遂川县| 溧水县| 商洛市| 桃江县| 都昌县| 曲周县| 灵宝市| 临漳县| 郓城县| 特克斯县|