欧美激情中文字幕在线_国产区精品视频_免费久久99精品国产自_日韩精品 欧美

ES6中的異步詳解

眾所周知JS是單線程的,這種設計讓JS避免了多線程的各種問題,但同時也讓JS同一時刻只能執行一個任務,若這個任務執行時間很長的話(如死循環),會導致JS直接卡死,在瀏覽器中的表現就是頁面無響應,用戶體驗非常之差。

因此,在JS中有兩種任務執行模式:同步(Synchronous)和異步(Asynchronous)。類似函數調用、流程控制語句、表達式計算等就是以同步方式運行的,而異步主要由setTimeout/setInterval、事件實現。

傳統的異步實現

作為一個前端開發者,無論是瀏覽器端還是Node,相信大家都使用過事件吧,通過事件肯定就能想到回調函數,它就是實現異步最常用、最傳統的方式。

不過要注意,不要以為回調函數就都是異步的,如ES5的數組方法Array.prototype.forEach((ele) => {})等等,它們也是同步執行的。回調函數只是一種處理異步的方式,屬于函數式編程中高階函數的一種,并不只在處理異步問題中使用。

舉個栗子?:

// 最常見的ajax回調
this.ajax('/path/to/api', {
    params: params
}, (res) => {
    // do something...
})

你可能覺得這樣并沒有什么不妥,但是若有多個ajax或者異步操作需要依次完成呢?

this.ajax('/path/to/api', {
    params: params
}, (res) => {
    // do something...
    this.ajax('/path/to/api', {
      params: params
    }, (res) => {
        // do something...
        this.ajax('/path/to/api', {
          params: params
        }, (res) => {
          // do something...
        })
        ...
    })
})

回調地獄就出現了。。。?

為了解決這個問題,社區中提出了Promise方案,并且該方案在ES6中被標準化,如今已廣泛使用。

Promise

使用Promise的好處就是讓開發者遠離了回調地獄的困擾,它具有如下特點:

  1. 對象的狀態不受外界影響:
    • Promise對象代表一個異步操作,有三種狀態:Pending(進行中)、Resolved(已完成,又稱 Fulfilled)和Rejected(已失敗)。
    • 只有異步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。
  2. 一旦狀態改變,就不會再變,任何時候都可以得到這個結果。
    • Promise對象的狀態改變,只有兩種可能:從Pending變為Resolved和從Pending變為Rejected。
    • 只要這兩種情況發生,狀態就凝固了,不會再變了,會一直保持這個結果。
    • 如果改變已經發生了,你再對Promise對象添加回調函數,也會立即得到這個結果。
    • 這與事件(Event)完全不同,事件的特點是,如果你錯過了它,再去監聽,是得不到結果的。
  3. 一旦聲明Promise對象(new Promise或Promise.resolve等),就會立即執行它的函數參數,若不是函數參數則不會執行
this.ajax('/path/to/api', {
    params: params
}).then((res) => {
    // do something...
    return this.ajax('/path/to/api', {
        params: params
    })
}).then((res) => {
    // do something...
    return this.ajax('/path/to/api', {
        params: params
    })
})
...

看起來就直觀多了,就像一個鏈條一樣將多個操作依次串了起來,再也不用擔心回調了~?

同時Promise還有許多其他API,如Promise.allPromise.racePromise.resolve/reject等等(可以參考阮老師的文章),在需要的時候配合使用都是極好的。

API無需多說,不過這里我總結了一下自己之前使用Promise踩到的坑以及我對Promise理解不夠透徹的地方,希望也能幫助大家更好地使用Promise:

1.then的返回結果:我之前天真的以為then要想鏈式調用,必須要手動返回一個新的Promise才行

Promise.resolve('first promise')
.then((data) => {
    // return Promise.resolve('next promise')
    // 實際上兩種返回是一樣的
    return 'next promise'
})
.then((data) => {
    console.log(data)
})

總結如下:

  • 如果then方法中返回了一個值,那么返回一個“新的”resolved的Promise,并且resolve回調函數的參數值是這個值
  • 如果then方法中拋出了一個異常,那么返回一個“新的”rejected狀態的Promise
  • 如果then方法返回了一個未知狀態(pending)的Promise新實例,那么返回的新Promise就是未知狀態
  • 如果then方法沒有返回值時,那么會返回一個“新的”resolved的Promise,但resolve回調函數沒有參數

2.一個Promise可設置多個then回調,會按定義順序執行,如下

const p = new Promise((res) => {
  res('hahaha')
})
p.then(console.log)
p.then(console.warn)

這種方式與鏈式調用不要搞混,鏈式調用實際上是then方法返回了新的Promise,而不是原有的,可以驗證一下:

const p1 = Promise.resolve(123)
const p2 = p1.then(() => {
    console.log(p1 === p2)
    // false
})

3.thencatch返回的值不能是當前promise本身,否則會造成死循環

const promise = Promise.resolve()
.then(() => {
    return promise
})

4.then或者catch的參數期望是函數,傳入非函數則會發生值穿透

Promise.resolve(1)
  .then(2)
  .then(Promise.resolve(3))
  .then(console.log)
// 1

5.process.nextTickpromise.then都屬于microtask,而setImmediatesetTimeout屬于macrotask

process.nextTick(() => {
  console.log('nextTick')
})
Promise.resolve()
  .then(() => {
    console.log('then')
  })
setImmediate(() => {
  console.log('setImmediate')
})
console.log('end')
// end nextTick then setImmediate

有關microtaskmacrotask可以看這篇文章,講得很細致。

但Promise也存在弊端,那就是若步驟很多的話,需要寫一大串.then(),盡管步驟清晰,但是對于我們這些追求極致優雅的前端開發者來說,代碼全都是Promise的API(thencatch),操作的語義太抽象,還是讓人不夠滿意呀~

Generator

Generator是ES6規范中對協程的實現,但目前大多被用于異步模擬同步上了。

執行它會返回一個遍歷器對象,而每次調用next方法則將函數執行到下一個yield的位置,若沒有則執行到return或末尾。

依舊是不再贅述API,對它還不了解的可以查閱阮老師的文章

通過Generator實現異步:

function* main() {
   const res = yield getData()
   console.log(res)
}
// 異步方法
function getData() {
   setTimeout(() => {
       it.next({
           name: 'yuanye',
           age: 22
       })
   }, 2000)
}
const it = main()
it.next()

先不管下面的next方法,單看main方法中,getData模擬的異步操作已經看起來很像同步了。但是追求完美的我們肯定是無法忍受每次還要手動調用next方法來繼續執行流程的,為此TJ大神為社區貢獻了co模塊來自動化執行Generator,它的實現原理非常巧妙,源碼只有短短的200多行,感興趣可以去研究下。

const co = require('co')

co(function* () {
  const res1 = yield ['step-1']
  console.log(res1)
  // 若yield后面返回的是promise,則會等待它resolved后繼續執行之后的流程
  const res2 = yield new Promise((res) => {
    setTimeout(() => {
      res('step-2')
    }, 2500)
  })
  console.log(res2)
  return 'end'
}).then((data) => {
  console.log('end: ' + data)
})

這樣就讓異步的流程完全以同步的方式展示出來啦?~

Async/Await

ES7標準中引入的async函數,是對js異步解決方案的進一步完善,它有如下特點:

  1. 內置執行器:不用像generator那樣反復調用next方法,或者使用co模塊,調用即會自動執行,并返回結果
  2. 返回Promise:generator返回的是iterator對象,因此還不能直接用then來指定回調
  3. await更友好:相比co模塊約定的generator的yield后面只能跟promise或thunk函數或者對象及數組,await后面既可以是promise也可以是任意類型的值(Object、Number、Array,甚至Error等等,不過此時等同于同步操作)

進一步說,async函數完全可以看作多個異步操作,包裝成的一個Promise對象,而await命令就是內部then命令的語法糖

改寫后代碼如下:

async function testAsync() {
  const res1 = await new Promise((res) => {
    setTimeout(() => {
      res('step-1')
    }, 2000)
  })
  console.log(res1)
  const res2 = await Promise.resolve('step-2')
  console.log(res2)
  const res3 = await new Promise((res) => {
    setTimeout(() => {
      res('step-3')
    }, 2000)
  })
  console.log(res3)
  return [res1, res2, res3, 'end']
}

testAsync().then((data) => {
  console.log(data)
})

這樣不僅語義還是流程都非常清晰,即便是不熟悉業務的開發者也能一眼看出哪里是異步操作。

總結

本文匯總了當前主流的JS異步解決方案,其實沒有哪一種方法最好或不好,都是在不同的場景下能發揮出不同的優勢。而且目前都是Promise與其他兩個方案配合使用的,所以不存在你只學會async/await或者generator就可以玩轉異步。沒準以后又會出現一個新的方案,將已有的這幾種方案顛覆呢 ~

說實話,學過后端的人玩JavaScript會陷入一種困境,如果讓程序員自己處理可能會更符合邏輯,比如引入線程之類的,不過優化起來又是一個問題了。。。

來源:https://blog.markeyme.cn/2018/06/09/ES6%E5%BC%82%E6%AD%A5%E6%96%B9%E5%BC%8F%E5%85%A8%E9%9D%A2%E8%A7%A3%E6%9E%90/

上一篇 FancyBox3 中文文檔
下一篇 JavaScript中函數后面打星號方式聲明
目錄
applek

applek管理員

個人說明在個人中心里面設置

本月創作熱力圖

最新評論
小超
小超
7月9日
下個版本考慮將下載地址加密(防止采集)
Lvtu
Lvtu
7月4日
qiang厲害
評論于留言建議
chinacnd
chinacnd
6月26日
這個主題是怎么做到加載速度那么快的?
風起云涌
風起云涌
6月17日
前臺投稿現在有點太抽象了 希望可以弄成那種分區填寫的 標題,內容,圖片,目錄,標簽,這樣的
評論于留言建議
主站蜘蛛池模板: 国产日韩欧美视频在线| 日韩久久久久久久久久久久久| 久久精品国产2020观看福利 | 久久国产精品亚洲va麻豆| 国产精品美女av| 日韩欧美一级在线| 91精品视频在线看| 久久亚洲国产精品日日av夜夜| 亚洲一区二区在线看| 国产精品av免费在线观看| 国产女人精品视频| 亚洲欧洲精品一区二区| 91精品视频播放| 97久久国产亚洲精品超碰热| 国产精品美女xx| 国产精品久久77777| 国产欧美日韩精品专区| 久久精品国产sm调教网站演员| 欧美精品中文字幕一区二区| 日本不卡在线观看| 少妇免费毛片久久久久久久久| **亚洲第一综合导航网站| 91久久久亚洲精品| 亚洲a级在线播放观看| 亚洲熟妇无码另类久久久| 日韩中文字幕亚洲| 欧美日韩精品免费观看视一区二区| 日韩av在线一区二区三区| 日韩不卡视频一区二区| 欧洲精品亚洲精品| 日本一区二区三区www| 欧洲中文字幕国产精品| 久久九九国产视频| 国产精品日本精品| 国产激情视频一区| 91av在线不卡| 欧美亚洲视频一区| 国产一区福利视频| 91麻豆国产精品| 欧美日韩亚洲一| 国模精品一区二区三区|