亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

新手如何快速理解js異步編程

 更新時間:2019年06月24日 10:53:15   作者:Yzz  
這篇文章主要介紹了新手如何快速理解js異步編程,異步編程從早期的 callback、事件發(fā)布\訂閱模式到 ES6 的 Promise、Generator 在到 ES2017 中 async,看似風(fēng)格迥異,但是還是有一條暗線將它們串聯(lián)在一起的,,需要的朋友可以參考下

前言

異步編程從早期的 callback、事件發(fā)布\訂閱模式到 ES6 的 Promise、Generator 在到 ES2017 中 async,看似風(fēng)格迥異,但是還是有一條暗線將它們串聯(lián)在一起的,就是希望將異步編程的代碼表達(dá)盡量地貼合自然語言的線性思維。

以這條暗線將上述幾種解決方案連在一起,就可以更好地理解異步編程的原理、魅力。
├── 事件發(fā)布\訂閱模式 <= Callback
├── Promise <= 事件發(fā)布\訂閱模式
├── Async、Await <= Promise、Generator

事件發(fā)布\訂閱模式 <= Callback

這個模式本質(zhì)上就是回調(diào)函數(shù)的事件化。它本身并無同步、異步調(diào)用的問題,我們只是使用它來實現(xiàn)事件與回調(diào)函數(shù)之間的關(guān)聯(lián)。比較典型的有 NodeJS 的 events 模塊

const { EventEmitter } = require('events')
const eventEmitter = new EventEmitter()
// 訂閱
eventEmitter.on("event", function(msg) {
console.log("event", msg)
})
// 發(fā)布
eventEmitter.emit("event", "Hello world")

那么這種模式是如何與 Callback 關(guān)聯(lián)的呢?我們可以利用 Javascript 簡單實現(xiàn) EventEmitter,答案就顯而易見了。

class usrEventEmitter {
constructor () {
this.listeners = {}
}
// 訂閱,callback 為每個 event 的偵聽器
on(eventName, callback) {
if (!this.listeners[eventName]) this.listeners[eventName] = []
this.listeners[eventName].push(callback)
}
// 發(fā)布
emit(eventName, params) {
this.listeners[eventName].forEach(callback => {
callback(params)
})
}
// 注銷
off(eventName, callback) {
const rest = this.listeners[eventName].fitler(elem => elem !== callback)
this.listeners[eventName] = rest
}
// 訂閱一次
once(eventName, callback) { 
const handler = function() {
callback()
this.off(eventName, handler)
}
this.on(eventName, handler)
}
}

上述實現(xiàn)忽略了很多細(xì)節(jié),例如異常處理、多參數(shù)傳遞等。只是為了展示事件訂閱\發(fā)布模式。

很明顯的看出,我們使用這種設(shè)計模式對異步編程做了邏輯上的分離,將其語義化為

// 一些事件可能會被觸發(fā)
eventEmitter.on
// 當(dāng)它發(fā)生的時候,要這樣處理
eventEmitter.emit

也就是說,我們將最初的 Callback 變成了事件監(jiān)聽器,從而優(yōu)雅地解決異步編程。

Promise <= 事件發(fā)布\訂閱模式

使用事件發(fā)布\訂閱模式時,需要我們事先嚴(yán)謹(jǐn)?shù)卦O(shè)置目標(biāo),也就是上面所說的,必須要縝密地設(shè)定好有哪些事件會發(fā)生。這與我們語言的線性思維很違和。那么有沒有一種方式可以解決這個問題,社區(qū)產(chǎn)出了 Promise。

const promise = new Promise(function(resolve, reject) {
try {
setTimeout(() => {
resolve('hello world')
}, 500)
} catch (error) {
reject(error)
}
})
// 語義就變?yōu)橄劝l(fā)生一些異步行為,then 我們應(yīng)該這么處理 promise.then(msg => console.log(msg)).catch(error => console.log('err', error))

那么這種 Promise 與事件發(fā)布\訂閱模式有什么聯(lián)系呢?我們可以利用 EventEmitter 來實現(xiàn) Promise,這樣可能會對你有所啟發(fā)。

我們可以將 Promise 視為一個 EventEmitter,它包含了 { state: 'pending' } 來描述當(dāng)前的狀態(tài),同時偵聽它的變化

  • 當(dāng)成功時 { state: 'fulfilled' },要做些什么 on('resolve', callback);
  • 當(dāng)失敗時 { state: 'rejected' },要做些什么 on('reject', callback)。

具體實現(xiàn)如下

const { EventEmitter } = require('events')
class usrPromise extends EventEmitter {
// 構(gòu)造時候執(zhí)行
constructor(executor) {
super()
// 發(fā)布
const resolve = (value) => this.emit('resolve', value)
const reject = (reason) => this.emit('reject', reason)
if (executor) {
// 模擬 event loop,注此處利用 Macrotask 來模擬 Microtask
setTimeout(() => executor(resolve, reject))
}
}
then(resolveHandler, rejectHandler) {
const nextPromise = new usrPromise()
// 訂閱 resolve 事件
if (resolveHandler) {
const resolve = (data) => {
const result = resolveHandler(data)
nextPromise.emit('resolve', result)
}
this.on('resolve', resolve)
}
// 訂閱 reject 事件
if (rejectHandler) {
const reject = (data) => {
const result = rejectHandler(data)
nextPromise.emit('reject', result)
}
this.on('reject', reject)
} else {
this.on('reject', (data) => {
promise.emit('reject', data)
})
}
return nextPromise
}
catch(handler) {
this.on('reject', handler)
}
}

我們使用 then 方法來將預(yù)先需要定義的事件偵聽器存放起來,同時在 executor 中設(shè)定這些事件該在什么時候?qū)嵭小?br />

可以看出從事件發(fā)布\訂閱模式到 Promise,帶來了語義上的巨大變革,但是還是需要使用 new Promise 來描述整個狀態(tài)的轉(zhuǎn)換,那么有沒有更好地實現(xiàn)方式呢?

async、await <= Promise、Generator

async、await 標(biāo)準(zhǔn)是 ES 2017 引入,提供一種更加簡潔的異步解決方案。

async function say(greeting) {
return new Promise(function(resolve, then) {
setTimeout(function() {
resolve(greeting)
}, 1500)
})
}
;(async function() {
let v1 = await say('Hello')
console.log(v1)
let v2 = await say('World')
console.log(v2)
})()

await 可以理解為暫停當(dāng)前 async function 的執(zhí)行,等待 Promise 處理完成。。若 Promise 正常處理(fulfilled),其回調(diào)的resolve函數(shù)參數(shù)作為 await 表達(dá)式的值。

async、await 的出現(xiàn),減少了多個 then 的鏈?zhǔn)秸{(diào)用形式的代碼。下面我們結(jié)合 Promise 與 Generator 來實現(xiàn) async、await

function async(makeGenerator) {
return function() {
const generator = makeGenerator.apply(this, arguments)
function handle({ value, done }) {
if (done === true) return Promise.resolve(value)
return Promise.resolve(value).then(
(res) => {
return handle(generator.next(res))
},
function(err) {
return handle(generator.throw(err))
}
)
}
try {
return handle(generator.next())
} catch (ex) {
return Promise.reject(ex)
}
}
}
async(function*() {
var v1 = yield say('hello')
console.log(1, v1)
var v2 = yield say('world')
console.log(2, v2)
})()

本質(zhì)上就是利用遞歸完成 function* () { ... } 的自動執(zhí)行。相比與 Generator 函數(shù),這種形式無需手動執(zhí)行,并且具有更好的語義。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,

相關(guān)文章

  • 解決js函數(shù)閉包內(nèi)存泄露問題的辦法

    解決js函數(shù)閉包內(nèi)存泄露問題的辦法

    這篇文章主要通過舉例介紹了解決js函數(shù)閉包內(nèi)存泄露問題的辦法,感興趣的小伙伴們可以參考一下
    2016-01-01
  • JS getStyle獲取最終樣式函數(shù)代碼

    JS getStyle獲取最終樣式函數(shù)代碼

    定義一個id="flower"的div元素 并設(shè)置如上樣式,我們的目標(biāo)就是通過javascript來獲取樣式的最終屬性
    2010-04-04
  • 深入理解在JS中通過四種設(shè)置事件處理程序的方法

    深入理解在JS中通過四種設(shè)置事件處理程序的方法

    所有的JavaScript事件處理程序的作用域是在其定義時的作用域而非調(diào)用時的作用域中執(zhí)行,并且它們能存取那個作用域中的任何一個本地變量。但是HTML標(biāo)簽屬性注冊處理程序就是一個例外。看下面四種方式
    2017-03-03
  • 深入淺析同源策略和跨域訪問

    深入淺析同源策略和跨域訪問

    同源策略(Same origin policy)是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能都會受到影響??梢哉fWeb是構(gòu)建在同源策略基礎(chǔ)之上的,瀏覽器只是針對同源策略的一種實現(xiàn)
    2015-11-11
  • TextArea設(shè)置MaxLength屬性最大輸入值的js代碼

    TextArea設(shè)置MaxLength屬性最大輸入值的js代碼

    TextArea中限制最大輸入長度,實現(xiàn)的方法種種,我們不在一一介紹,今天本文推薦一種簡單實用的方法,需要的朋友可以參考下
    2012-12-12
  • 淺談如何使用 webpack 優(yōu)化資源

    淺談如何使用 webpack 優(yōu)化資源

    本篇文章主要介紹了淺談如何使用 webpack 優(yōu)化資源,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • 微信小程序完美解決scroll-view高度自適應(yīng)問題的方法

    微信小程序完美解決scroll-view高度自適應(yīng)問題的方法

    這篇文章主要介紹了微信小程序完美解決scroll-view高度自適應(yīng)問題的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • js實現(xiàn)Select頭像選擇實時預(yù)覽代碼

    js實現(xiàn)Select頭像選擇實時預(yù)覽代碼

    這篇文章主要介紹了js實現(xiàn)Select頭像選擇實時預(yù)覽代碼,涉及javascript動態(tài)遍歷及設(shè)置select選項的技巧,非常簡單實用,需要的朋友可以參考下
    2015-08-08
  • javascript中encodeURI和decodeURI方法使用介紹

    javascript中encodeURI和decodeURI方法使用介紹

    encodeURI和decodeURI是成對來使用的,因為瀏覽器的地址欄有中文字符的話,可以會出現(xiàn)不可預(yù)期的錯誤,所以可以encodeURI把非英文字符轉(zhuǎn)化為英文編碼,decodeURI可以用來把字符還原回來
    2013-05-05
  • 使用window.postMessage()方法在兩個網(wǎng)頁間傳遞數(shù)據(jù)

    使用window.postMessage()方法在兩個網(wǎng)頁間傳遞數(shù)據(jù)

    這篇文章介紹了使用window.postMessage()在兩個網(wǎng)頁間傳遞數(shù)據(jù)的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-06-06

最新評論