精品人伦一区二区三区蜜桃视频_日韩精品视频在线_www.色综合_久久久久久一区_aaaaaa黄色片_亚洲精品久久

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/

THE END
主站蜘蛛池模板: 精品伊人久久 | 久久精品国产一区二区电影 | 国产一区二区在线免费观看 | 天天视频一区二区三区 | 色黄爽 | 国产精品精品久久久 | 日本在线免费看最新的电影 | 天堂三级 | 久久午夜国产精品www忘忧草 | 狠狠影院 | 成人性视频免费网站 | 91久久久久久久久久久久久 | 天天综合国产 | 香蕉视频一区二区 | 久久久久久高潮国产精品视 | 91人人视频在线观看 | 欧美日韩久久精品 | 免费一级黄色录像 | 日韩精品区 | 97日日碰人人模人人澡分享吧 | 欧美久久久网站 | av一区二区三区四区 | 91精品国产91久久久久久最新 | 成人字幕网zmw | 亚洲欧美久久 | 成人午夜毛片 | 国产精品久久久久久久免费观看 | 国产精品日韩欧美一区二区三区 | 成人自拍视频网站 | 麻豆久久久久久久 | 久久在线 | 欧美亚洲综合久久 | 欧美一区二区三区在线 | 成人免费看电影 | 毛片国产 | 99久久国产综合精品麻豆 | a级片在线观看 | 韩国成人在线视频 | 一区二区在线免费观看 | 91成人在线 | 国产成人高清在线观看 |