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

JavaScript異步拆解之Event-Loop+async/await

 更新時(shí)間:2026年03月30日 08:52:07   作者:不甜情歌  
JS異步本質(zhì)是單線程下的生存策略,主線程串行執(zhí)行,耗時(shí)操作交由宿主后臺(tái)處理,通過(guò)事件循環(huán)(微/宏任務(wù)調(diào)度)保障交互不卡頓,這篇文章主要介紹了JavaScript異步拆解之Event-Loop+async/await的相關(guān)資料,需要的朋友可以參考下

前言

在前端開(kāi)發(fā)中,是不是經(jīng)常被JS的異步代碼繞暈?明明寫(xiě)的代碼順序一樣,運(yùn)行結(jié)果卻大相徑庭?其實(shí)核心原因就在于——JS是單線程語(yǔ)言,而異步操作全靠「Event-Loop(事件循環(huán))」來(lái)調(diào)度。今天就結(jié)合具體代碼案例,從進(jìn)程線程、V8引擎到Event-Loop、async/await,一步步拆解,讓你搞懂JS異步的底層邏輯~

一、先基礎(chǔ):進(jìn)程 vs 線程

在聊JS異步之前,我們得先分清兩個(gè)容易混淆的概念:進(jìn)程和線程,這是理解后續(xù)內(nèi)容的基石~

  • 進(jìn)程 :簡(jiǎn)單來(lái)說(shuō),進(jìn)程就是CPU運(yùn)行指令、加載和保存上下文所需的“容器”,是程序運(yùn)行的獨(dú)立單位。比如你打開(kāi)瀏覽器,每多開(kāi)一個(gè)Tab頁(yè),就相當(dāng)于多開(kāi)啟了一個(gè)進(jìn)程,每個(gè)進(jìn)程之間相互獨(dú)立,互不干擾。

  • 線程 :線程是進(jìn)程內(nèi)的執(zhí)行單元,是CPU實(shí)際執(zhí)行指令的“最小單位”。一個(gè)進(jìn)程可以包含多個(gè)線程,這些線程共享進(jìn)程的資源,協(xié)同完成任務(wù)。

舉個(gè)瀏覽器的例子:每個(gè)瀏覽器Tab進(jìn)程中,會(huì)包含多個(gè)核心線程,其中和我們JS相關(guān)的有3個(gè):

  1. 渲染線程:負(fù)責(zé)渲染頁(yè)面(HTML、CSS渲染);

  2. JS引擎線程:負(fù)責(zé)執(zhí)行JS代碼;

  3. HTTP請(qǐng)求線程:負(fù)責(zé)發(fā)送網(wǎng)絡(luò)請(qǐng)求。

這里有個(gè)關(guān)鍵知識(shí)點(diǎn)??:因?yàn)镴S代碼可以修改DOM(比如document.write、appendChild),如果JS引擎線程和渲染線程同時(shí)運(yùn)行,會(huì)導(dǎo)致頁(yè)面渲染混亂,所以JS引擎線程和渲染線程是互斥的——也就是說(shuō),JS代碼執(zhí)行時(shí),渲染線程會(huì)暫停,等JS執(zhí)行完,渲染線程才會(huì)繼續(xù)工作。這也是為什么有時(shí)候JS代碼寫(xiě)得太復(fù)雜,頁(yè)面會(huì)出現(xiàn)“卡頓”的原因~

二、V8引擎:JS單線程的“幕后推手”

我們寫(xiě)的JS代碼,最終是由V8引擎來(lái)執(zhí)行的。而V8引擎在執(zhí)行JS代碼時(shí),默認(rèn)只開(kāi)啟一個(gè)JS引擎線程——這就意味著,JS代碼只能“自上而下、依次執(zhí)行”,同一時(shí)間只能做一件事。

那問(wèn)題來(lái)了:如果JS遇到耗時(shí)操作(比如setTimeout、網(wǎng)絡(luò)請(qǐng)求、讀取文件),難道要一直等著操作完成,再繼續(xù)執(zhí)行后續(xù)代碼嗎?這樣會(huì)導(dǎo)致頁(yè)面卡死,用戶體驗(yàn)直接拉胯!

為了解決這個(gè)問(wèn)題,JS引入了「異步機(jī)制」:?jiǎn)尉€程處理代碼時(shí),遇到同步任務(wù),就立即執(zhí)行;遇到異步任務(wù),不等待、不阻塞,而是把它暫時(shí)存放到“任務(wù)隊(duì)列”中,等JS引擎線程空閑時(shí),再去執(zhí)行任務(wù)隊(duì)列中的異步任務(wù)。

三、核心重點(diǎn):Event-Loop 事件循環(huán)

Event-Loop(事件循環(huán))就是JS處理異步任務(wù)的“調(diào)度器”,它的執(zhí)行流程決定了所有同步、異步代碼的運(yùn)行順序。我們先明確兩個(gè)核心概念:微任務(wù)宏任務(wù)——所有異步任務(wù),都會(huì)被分到這兩個(gè)隊(duì)列中。

3.1 微任務(wù) vs 宏任務(wù)

微任務(wù)和宏任務(wù)的區(qū)別,在于它們的“優(yōu)先級(jí)”:微任務(wù)優(yōu)先級(jí)高于宏任務(wù),會(huì)先于宏任務(wù)執(zhí)行。

  • 微任務(wù)(優(yōu)先級(jí)高)

    • Promise.then()、Promise.catch()、Promise.finally()

    • process.nextTick()(Node.js環(huán)境,瀏覽器不支持)

    • MutationObserver(監(jiān)聽(tīng)DOM變化的API)

  • 宏任務(wù)(優(yōu)先級(jí)低)

    • 整個(gè)script腳本(最外層的同步代碼,屬于宏任務(wù)的開(kāi)端)

    • setTimeout()、setInterval()

    • AJAX請(qǐng)求、I/O操作(比如讀取文件)

    • UI渲染(頁(yè)面渲染操作)

    易錯(cuò)點(diǎn)提醒??:很多人會(huì)誤以為“setTimeout(fn, 0)”會(huì)立即執(zhí)行,其實(shí)不然——setTimeout的延遲時(shí)間是“最小延遲”,不是“精確延遲”,即使設(shè)為0,也會(huì)被放入宏任務(wù)隊(duì)列,等待同步代碼、微任務(wù)全部執(zhí)行完畢后,才會(huì)執(zhí)行。

3.2 Event-Loop 執(zhí)行順序

記住這個(gè)順序,就能搞定80%的異步代碼輸出題,結(jié)合后面的代碼案例理解更透徹??:

  1. 先執(zhí)行同步代碼(最外層script腳本,屬于宏任務(wù)),執(zhí)行過(guò)程中遇到異步任務(wù),就分別存入微任務(wù)隊(duì)列、宏任務(wù)隊(duì)列;

  2. 同步代碼執(zhí)行完畢后,清空微任務(wù)隊(duì)列(所有微任務(wù)依次執(zhí)行,執(zhí)行過(guò)程中產(chǎn)生的新微任務(wù),也會(huì)在本次微任務(wù)隊(duì)列中執(zhí)行完畢);

  3. 微任務(wù)全部執(zhí)行結(jié)束后,若有需要(如DOM發(fā)生變化),瀏覽器會(huì)進(jìn)行頁(yè)面渲染;

  4. 渲染完成后,從宏任務(wù)隊(duì)列中取出第一個(gè)宏任務(wù)執(zhí)行(執(zhí)行該宏任務(wù)的過(guò)程中,遇到同步、異步任務(wù),重復(fù)步驟1-2);

  5. 重復(fù)步驟1-4,形成“循環(huán)”,這就是Event-Loop。

3.3 代碼實(shí)操:搞懂Event-Loop執(zhí)行順序

結(jié)合你給出的第一段代碼,我們一步步拆解執(zhí)行過(guò)程,看看為什么輸出結(jié)果是「1 2 7 3 5 4 6」:

console.log(1); // 同步代碼:輸出1
new Promise((resolve) => {
  console.log(2); // Promise構(gòu)造函數(shù)內(nèi)是同步代碼:輸出2
  resolve()
})
.then(() => {
  console.log(3); // 微任務(wù):存入微任務(wù)隊(duì)列
  setTimeout(() => {
    console.log(4); // 宏任務(wù):存入宏任務(wù)隊(duì)列(延遲0ms)
  }, 0)
})
setTimeout(() => {
  console.log(5); // 宏任務(wù):存入宏任務(wù)隊(duì)列(延遲0ms)
  setTimeout(() => {
    console.log(6); // 宏任務(wù):存入宏任務(wù)隊(duì)列(延遲0ms)
  }, 0)
}, 0)
console.log(7); // 同步代碼:輸出7

執(zhí)行步驟拆解??:

  1. console.log(1):同步,輸出「1」;

  2. new Promise:構(gòu)造函數(shù)內(nèi)是同步代碼,console.log(2),輸出「2」;調(diào)用resolve(),將then回調(diào)存入微任務(wù)隊(duì)列(記為微1);

  3. 遇到setTimeout(延遲0ms):宏任務(wù),存入宏任務(wù)隊(duì)列(記為宏1);

  4. console.log(7):同步,輸出「7」;

  5. 同步代碼執(zhí)行完畢,開(kāi)始清空微任務(wù)隊(duì)列:執(zhí)行微1(then回調(diào)),console.log(3),輸出「3」;遇到setTimeout(延遲0ms),宏任務(wù),存入宏任務(wù)隊(duì)列(記為宏2);

  6. 微任務(wù)隊(duì)列清空,渲染頁(yè)面(本次無(wú)明顯渲染);

  7. 執(zhí)行宏任務(wù)隊(duì)列第一個(gè)宏任務(wù)(宏2):console.log(5),輸出「5」;遇到setTimeout(延遲0ms),宏任務(wù),存入宏任務(wù)隊(duì)列(記為宏3);

  8. 宏2執(zhí)行完畢,再次檢查微任務(wù)隊(duì)列(無(wú)新微任務(wù)),執(zhí)行下一個(gè)宏任務(wù)(宏2):console.log(4),輸出「4」;

  9. 宏3執(zhí)行完畢,檢查微任務(wù)隊(duì)列(無(wú)),執(zhí)行下一個(gè)宏任務(wù)(宏3):console.log(6),輸出「6」。

所以最終輸出順序就是:1 2 7 3 5 4 6 ?

3.4 再練一題:鞏固Event-Loop

再看這段代碼??:

console.log(1);
setTimeout(() => {
  console.log(2);
  setTimeout(() => {
    console.log(3)
  }, 1000)
}, 0)
setTimeout(() => {
  console.log(4)
}, 2000)
console.log(5);

執(zhí)行步驟拆解??:

  1. 執(zhí)行同步代碼:console.log(1) → 輸出 1;

  2. 遇到第一個(gè) setTimeout(..., 0):延遲 0ms 后,把回調(diào)(輸出 2 + 嵌套定時(shí)器)推入宏任務(wù)隊(duì)列;

  3. 遇到第二個(gè) setTimeout(..., 2000):延遲 2000ms 后,把回調(diào)(輸出 4)推入宏任務(wù)隊(duì)列;

  4. 執(zhí)行同步代碼:console.log(5) → 輸出 5

  5. 同步代碼執(zhí)行完畢,開(kāi)始處理宏任務(wù)隊(duì)列

    • 取出第一個(gè)宏任務(wù):執(zhí)行 → 輸出 2;
    • 執(zhí)行中遇到嵌套的 setTimeout(..., 1000):延遲 1000ms 后,把回調(diào)(輸出 3)推入宏任務(wù)隊(duì)列;
  6. 此時(shí)宏任務(wù)隊(duì)列里,只有「延遲 2000ms 的輸出 4」在等待;

  7. 時(shí)間流逝:

    • 1000ms 到:輸出3 被推入宏任務(wù)隊(duì)列 → 立刻執(zhí)行 → 輸出 3;
    • 再等 1000ms(總計(jì) 2000ms):輸出4 被推入宏任務(wù)隊(duì)列 → 執(zhí)行 → 輸出 4。

最終輸出順序:1 → 5 → 2 → 3 → 4

宏任務(wù)隊(duì)列是先進(jìn)先出,為什么 3 比 4 先輸出?

關(guān)鍵點(diǎn):兩個(gè)定時(shí)器不是同時(shí)入隊(duì)

  • 輸出 4 的定時(shí)器:一開(kāi)始就設(shè)定了 2000ms 延遲,2000ms 后才入隊(duì);
  • 輸出 3 的定時(shí)器:等第一個(gè)宏任務(wù)執(zhí)行完(瞬間完成),才設(shè)定 1000ms 延遲,1000ms 后就入隊(duì)執(zhí)行。1000ms < 2000ms,所以 3 必然比 4 先執(zhí)行,和宏任務(wù)隊(duì)列順序無(wú)關(guān)。

JavaScript 中setTimeout的延遲時(shí)間是回調(diào)函數(shù)加入宏任務(wù)隊(duì)列的等待時(shí)間,而非執(zhí)行時(shí)間;宏任務(wù)隊(duì)列遵循先進(jìn)先出,但不同定時(shí)器的回調(diào)不是同時(shí)入隊(duì),誰(shuí)的延遲時(shí)間先耗盡,誰(shuí)就先入隊(duì)先執(zhí)行。

四、進(jìn)階:async/await 異步語(yǔ)法糖

async/await 是ES7引入的異步語(yǔ)法,本質(zhì)是Promise的“語(yǔ)法糖”,讓異步代碼寫(xiě)起來(lái)更像同步代碼,可讀性大大提升。

4.1 async/await 核心規(guī)則

  • async關(guān)鍵字:函數(shù)前面加async,等同于函數(shù)內(nèi)部自動(dòng)返回一個(gè)Promise實(shí)例對(duì)象。比如: async function fn() { return 1; // 等同于 return Promise.resolve(1); } fn().then(res => console.log(res)); // 輸出1

  • await關(guān)鍵字:必須跟async配合使用,不能單獨(dú)使用;如果await后面接的不是Promise對(duì)象,await就無(wú)法“約束”它,會(huì)直接執(zhí)行后續(xù)代碼;如果await后面接Promise對(duì)象,會(huì)“暫停”當(dāng)前async函數(shù)的執(zhí)行,等待Promise狀態(tài)變?yōu)閞esolved(成功)或rejected(失?。?,再繼續(xù)執(zhí)行后續(xù)代碼。

  • 關(guān)鍵原理:await fn() 之所以能“當(dāng)成同步看待”,核心是——await會(huì)把它后續(xù)的代碼(當(dāng)前async函數(shù)內(nèi),await后面的所有代碼),擠到微任務(wù)隊(duì)列中,等await后面的Promise執(zhí)行完成后,再執(zhí)行這個(gè)微任務(wù)。

4.2 代碼實(shí)操:async/await 執(zhí)行順序

先看這段基礎(chǔ)代碼,理解async/await和Promise的關(guān)聯(lián):

function a() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('a'); // 宏任務(wù)
      resolve()
    }, 1000)
  })
}
function b() {
  console.log('b'); // 同步
}
// 案例1:Promise.then寫(xiě)法
a().then(() => {
  b()
})
console.log('hello'); // 同步

輸出順序:hello → a → b(同步代碼先執(zhí)行,a()是Promise,then回調(diào)是微任務(wù),等待a()的宏任務(wù)執(zhí)行完,再執(zhí)行微任務(wù)b())

再看async/await寫(xiě)法,對(duì)比差異:

function a() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('a'); // 宏任務(wù)
      resolve()
    }, 1000)
  })
}
function b() {
  console.log('b'); // 同步
}
async function foo() {
  setTimeout(() => {
    console.log('c'); // 宏任務(wù)(延遲1500ms)
  }, 1500)
  await a()  // 等待a()的Promise resolve,后續(xù)代碼進(jìn)入微任務(wù)
  b()
  console.log('hello');
}
foo()

執(zhí)行步驟拆解??:

  1. 調(diào)用foo(),執(zhí)行async函數(shù)內(nèi)部代碼;

  2. 遇到setTimeout(延遲1500ms):宏任務(wù),存入宏任務(wù)隊(duì)列(記為宏A);

  3. 遇到await a():a()返回Promise,里面有setTimeout(延遲1000ms,宏任務(wù),記為宏B);此時(shí)foo()暫停執(zhí)行,等待宏B執(zhí)行完畢、Promise resolve;

  4. 同步代碼執(zhí)行完畢(此時(shí)foo()暫停,無(wú)其他同步代碼),檢查微任務(wù)隊(duì)列(無(wú)),執(zhí)行宏任務(wù)隊(duì)列;

  5. 先執(zhí)行宏B(延遲1000ms):console.log('a'),輸出「a」;調(diào)用resolve(),此時(shí)await等待結(jié)束,將foo()后續(xù)的代碼(b()、console.log('hello'))存入微任務(wù)隊(duì)列;

  6. 宏B執(zhí)行完畢,檢查微任務(wù)隊(duì)列,執(zhí)行微任務(wù):b()輸出「b」,console.log('hello')輸出「hello」;

  7. 微任務(wù)執(zhí)行完畢,執(zhí)行下一個(gè)宏任務(wù)(宏A,延遲1500ms):console.log('c'),輸出「c」。

最終輸出順序:a → b → hello → c ?

4.3 綜合案例:async/await + Promise + setTimeout

console.log('script start'); // 同步
async function async1() {
  await async2() // 等待async2()執(zhí)行,后續(xù)代碼進(jìn)入微任務(wù)
  console.log('async1 end'); // 微任務(wù)
}
async function async2() {
  console.log('async2 end'); // 同步(async函數(shù)內(nèi),await前的代碼是同步)
}
async1()
setTimeout(() => {
  console.log('setTimeout'); // 宏任務(wù)
}, 0)
new Promise((resolve, reject) => {
  console.log('promise'); // 同步
  resolve()
})
  .then(() => {
    console.log('then1'); // 微任務(wù)
  })
  .then(() => {
    console.log('then2'); // 微任務(wù)(then1執(zhí)行完后存入)
  }); 
console.log('script end'); // 同步

輸出順序:script start → async2 end → promise → script end → async1 end → then1 → then2 → setTimeout

?? 關(guān)鍵提醒:async函數(shù)內(nèi),await前面的代碼是同步執(zhí)行的;await后面的代碼會(huì)被放入微任務(wù)隊(duì)列,和Promise.then的微任務(wù)優(yōu)先級(jí)相同,按順序執(zhí)行。

五、總結(jié):異步核心知識(shí)點(diǎn)梳理

1. JS是單線程,由V8引擎的JS引擎線程執(zhí)行,與渲染線程互斥;

2. 異步任務(wù)分為微任務(wù)(優(yōu)先級(jí)高)和宏任務(wù)(優(yōu)先級(jí)低);

3. Event-Loop執(zhí)行順序:同步代碼 → 微任務(wù)隊(duì)列 → 頁(yè)面渲染 → 宏任務(wù)隊(duì)列(循環(huán));

4. async/await是Promise語(yǔ)法糖,await會(huì)將后續(xù)代碼放入微任務(wù)隊(duì)列,等待Promise resolve后執(zhí)行。

到此這篇關(guān)于JavaScript異步拆解之Event-Loop+async/await的文章就介紹到這了,更多相關(guān)JS異步Event-Loop+async/await內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JavaScript判斷數(shù)據(jù)類型的四種方式總結(jié)

    JavaScript判斷數(shù)據(jù)類型的四種方式總結(jié)

    JavaScript 作為一門動(dòng)態(tài)語(yǔ)言,其靈活性是把雙刃劍,一方面帶來(lái)了開(kāi)發(fā)的便利性,另一方面也給我們?cè)陬愋团袛鄷r(shí)帶來(lái)了挑戰(zhàn),特別是在處理類型轉(zhuǎn)換和隱式轉(zhuǎn)換的時(shí)候,所以本篇文章我們將探討 JavaScript 中的數(shù)據(jù)類型判斷方式及在實(shí)際項(xiàng)目中的應(yīng)用,需要的朋友可以參考下
    2025-04-04
  • ajax在js中和jQuery中的用法實(shí)例詳解

    ajax在js中和jQuery中的用法實(shí)例詳解

    Ajax被認(rèn)為是(Asynchronous(異步) JavaScript And Xml的縮寫(xiě)),現(xiàn)在允許瀏覽器與服務(wù)器通信而無(wú)須刷新當(dāng)前頁(yè)面的技術(shù)都被叫做Ajax,下面這篇文章主要給大家介紹了關(guān)于ajax在js中和jQuery中的用法,需要的朋友可以參考下
    2021-08-08
  • try finally 妙用,防止內(nèi)存泄漏

    try finally 妙用,防止內(nèi)存泄漏

    預(yù)防內(nèi)存泄漏
    2008-03-03
  • javascript生成隨機(jī)大小寫(xiě)字母的方法

    javascript生成隨機(jī)大小寫(xiě)字母的方法

    這篇文章主要介紹了javascript生成隨機(jī)大小寫(xiě)字母的方法,需要的朋友可以參考下
    2014-02-02
  • PHP實(shí)現(xiàn)基于Redis的MessageQueue隊(duì)列封裝操作示例

    PHP實(shí)現(xiàn)基于Redis的MessageQueue隊(duì)列封裝操作示例

    這篇文章主要介紹了PHP實(shí)現(xiàn)基于Redis的MessageQueue隊(duì)列封裝操作,結(jié)合實(shí)例形式分析了Redis的PHP消息隊(duì)列封裝與使用相關(guān)操作技巧,需要的朋友可以參考下
    2019-02-02
  • JS彈出層的顯示與隱藏示例代碼

    JS彈出層的顯示與隱藏示例代碼

    關(guān)于JS彈出層的顯示與隱藏,在網(wǎng)上可以搜到很多的類似教程,本文實(shí)現(xiàn)了一下,喜歡的朋友不要錯(cuò)過(guò)
    2013-12-12
  • AJAX XMLHttpRequest對(duì)象創(chuàng)建使用詳解

    AJAX XMLHttpRequest對(duì)象創(chuàng)建使用詳解

    這篇文章主要介紹了AJAX XMLHttpRequest對(duì)象創(chuàng)建使用詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • 微信小程序修改swiper默認(rèn)指示器樣式的實(shí)例代碼

    微信小程序修改swiper默認(rèn)指示器樣式的實(shí)例代碼

    這篇文章主要介紹了微信小程序修改swiper默認(rèn)指示器樣式的實(shí)例代碼,代碼塊是從微信開(kāi)發(fā)文檔中心復(fù)制的代碼塊,在此基礎(chǔ)上修改官方swiper樣式,需要的朋友可以參考下
    2018-07-07
  • JavaScript設(shè)置IFrame高度自適應(yīng)(兼容各主流瀏覽器)

    JavaScript設(shè)置IFrame高度自適應(yīng)(兼容各主流瀏覽器)

    IFrame高度的設(shè)置問(wèn)題一直都是前端的噩夢(mèng)而且還要兼容各主流瀏覽器更是難上加難了,下面與大家分享下一個(gè)不錯(cuò)的技巧,感興趣的你可以參考下哈
    2013-06-06
  • JavaScript數(shù)組與對(duì)象方法完全指南

    JavaScript數(shù)組與對(duì)象方法完全指南

    JavaScript 中的數(shù)組和對(duì)象是開(kāi)發(fā)中最常用的數(shù)據(jù)結(jié)構(gòu),掌握它們的方法對(duì)于高效編程至關(guān)重要,本文將深入解析各種數(shù)組和對(duì)象方法,提供詳細(xì)的概念解釋、參數(shù)說(shuō)明和實(shí)用代碼示例,并按照功能進(jìn)行分組展示,需要的朋友可以參考下
    2025-06-06

最新評(píng)論

博客| 临泉县| 尼玛县| 边坝县| 美姑县| 六枝特区| 桐城市| 长武县| 循化| 孝昌县| 安乡县| 梓潼县| 叙永县| 方城县| 鹿泉市| 隆子县| 马龙县| 吴江市| 乌兰浩特市| 阿坝县| 呼玛县| 察隅县| 阜新市| 甘泉县| 汤原县| 兰州市| 湖口县| 衡水市| 大新县| 寿宁县| 临城县| 凤台县| 南江县| 天祝| 营山县| 泗阳县| 大渡口区| 双牌县| 崇礼县| 铁岭市| 徐州市|