成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

山寨一個 Promise

XFLY / 2777人閱讀

摘要:其次要記錄狀態(tài),判斷消息是否已被發(fā)布,如果未發(fā)布消息,則通過來注冊回調(diào)時,是將回調(diào)函數(shù)添加到內(nèi)部的回調(diào)隊列中如果消息已發(fā)布,則通過來注冊回調(diào)時,直接將消息傳至回調(diào)函數(shù),并執(zhí)行規(guī)范中采用的狀態(tài)機制是可以轉(zhuǎn)化為或,并且只能轉(zhuǎn)化一次。

一點感悟

Promise 是編寫異步的另一種方式,鄙人愚見,它就是 Callback 的一種封裝

相比 Callback ,它有以下特點

Promise 將異步結(jié)果保存起來,可以隨時獲取

鏈?zhǔn)秸{(diào)用 then 方法會返回一個新的 Promise ,從而避免了回調(diào)地獄

決定一次異步有兩個環(huán)節(jié)

發(fā)起異步事件

處理異步結(jié)果

Promise 可以給一個異步事件注冊多個處理函數(shù),舉個栗子,就像這樣

let p1 = new Promise((resolve) => {
  fs.readFile("./test.js", "utf8", (err, data) => {
    resolve(data)
  })
})
p1.then(data => console.log(data))
p1.then(data => console.log(data.toUpperCase()))

用 Callback 實現(xiàn)一樣的效果

用 callbacks 將所有注冊的函數(shù)保存

待異步事件返回結(jié)果,再遍歷 callbacks ,依次執(zhí)行所有注冊的函數(shù)

就像這樣

let callbacks = []
function resolve(data){
  callbacks.forEach(cb => cb(data))
}

fs.readFile("./test.js", "utf8", (err, data) => {
  resolve(data)
})

callbacks.push(data => console.log(data))
callbacks.push(data => console.log(data.toUpperCase()))

將上述代碼封裝一下

const fs = require("fs")

class FakePromise {
  constructor(fn){
      this.callbacks = []
      resolve = resolve.bind(this)
    function resolve(data){
      this.callbacks.forEach(cb => cb(data))
    }
    fn(resolve)
  }
  
  then(onFulfilled){
    this.callbacks.push(onFulfilled)
  }
}

let p1 = new FakePromise(resolve => {
  fs.readFile("./test.js", "utf8", (err, data) => {
    resolve(data)
  })
})
p1.then(data => console.log(data))
p1.then(data => console.log(data.toUpperCase()))

哈?是不是和真的 Promise 有點像

從發(fā)布-訂閱模式的角度來看:

FakePromise 中通過 .then(onFulfilled) 來訂閱消息,注冊處理異步結(jié)果的函數(shù)

通過 resolve(data) 來發(fā)布消息,觸發(fā)處理異步結(jié)果的函數(shù)去執(zhí)行,發(fā)布的時機是異步事件完成時

延時 resolve

先前的代碼存在一個問題,如果在執(zhí)行 p1.then(data => console.log(data)) 之前,resolve(data) 就已經(jīng)執(zhí)行了,那么再通過 .then(onFulfilled) 注冊的處理異步結(jié)果的函數(shù)將永遠不會執(zhí)行

為了避免這種情況,改造 resolve 函數(shù),在其內(nèi)部添加 setTimeout,從而保證那些注冊的處理函數(shù)是在下一個事件隊列中執(zhí)行,就像這樣

function resolve(value) {
    setTimeout(() => {
        this.callbacks.forEach(cb => cb(value))
    }, 0)
}

通過延時執(zhí)行 resolve 內(nèi)部的函數(shù),保證了先訂閱消息,再發(fā)布消息

但是 Promise 還有個額外的功能是在發(fā)布消息后,仍然可以訂閱消息,并且立即執(zhí)行,就像這樣

const fs = require("fs")

let p1 = new Promise(resolve => {
    fs.readFile("./test.js", "utf8", (err, data) => resolve(data))
})

p1.then(data => console.log(data))
setTimeout(function(){
    p1.then(data => console.log(data.toUpperCase()))
}, 5000)

5s之內(nèi),文件早已讀取成功,但是在5s之后,依然可以通過 .then 注冊處理事件,并且該事件會立即執(zhí)行

先發(fā)布,再訂閱

實現(xiàn)先發(fā)布,再訂閱的基礎(chǔ)是將消息保存下來。其次要記錄狀態(tài),判斷消息是否已被發(fā)布,如果未發(fā)布消息,則通過 .then 來注冊回調(diào)時,是將回調(diào)函數(shù)添加到內(nèi)部的回調(diào)隊列中;如果消息已發(fā)布,則通過 .then 來注冊回調(diào)時,直接將消息傳至回調(diào)函數(shù),并執(zhí)行

Promise 規(guī)范中采用的狀態(tài)機制是 pendingfulfilled、rejected

pending 可以轉(zhuǎn)化為 fulfilledrejected ,并且只能轉(zhuǎn)化一次。

轉(zhuǎn)化為 fulfilledrejected 后,狀態(tài)就不可再變

修改代碼如下

class FakePromise {
    constructor(fn) {
        this.value = null
        this.state = "pending"
        this.callbacks = []
        resolve = resolve.bind(this)

        function resolve(value) {
            setTimeout(() => {
                this.value = value
                this.state = "fulfilled"
                this.callbacks.forEach(cb => cb(value))
            }, 0)
        }
        fn(resolve)
    }

    then(onFulfilled) {
        if (this.state === "pending") {
            this.callbacks.push(onFulfilled)
        } else {
            onFulfilled(this.value)
        }
    }
}

既然實現(xiàn)了先發(fā)布,再訂閱,那么 resolve 中的 setTimeout 是不是可以去掉了?

并不可以,因為人家正經(jīng)的 Promise 是這樣的

let p1 = new Promise(resolve => {
    resolve("haha")
})
p1.then(data => console.log(data))
p1.then(data => console.log(data.toUpperCase()))
console.log("xixi")
// xixi
// haha
// HAHA

只有保留 resolve 中 setTimeout 才能使 FakePromise 實現(xiàn)相同的效果

let p1 = new FakePromise(resolve => {
    resolve("haha")
})
p1.then(data => console.log(data))
p1.then(data => console.log(data.toUpperCase()))
console.log("xixi")
// xixi
// haha
// HAHA

沒有 setTimeout 的輸出結(jié)果

// haha
// HAHA
// xixi
鏈?zhǔn)?Promise

正經(jīng)的 Promise 可以鏈?zhǔn)秸{(diào)用,從而避免了回調(diào)地獄

let p1 = new Promise(resolve => {
    fs.readFile("./test.js", "utf8", (err, data) => {
        resolve(data)
    })
}).then(res => {
    return new Promise(resolve => {
        fs.readFile("./main.js", "utf8", (err, data) => {
            resolve(data)
        })
    })
}).then(res => {
    console.log(res)
})

正經(jīng)的 Promise 調(diào)用 then 方法會返回一個新的 Promise 對象

我們偽造的 FakePromise 并沒有實現(xiàn)這一功能,原來的 then 方法

...
    then(onFulfilled){
        if (this.state === "pending") {
            this.callbacks.push(onFulfilled)
        } else {
            onFulfilled(this.value)
        }
    }
...

原來的 then 方法就是根據(jù) state 判斷是注冊 onFulfilled 函數(shù),還是執(zhí)行 onFulfilled 函數(shù)

為了實現(xiàn) FakePromise 的高仿,我們要改造 then 方法,使其返回一個新的 FakePromise ,為了方便區(qū)分,將返回的 FakePromise 取名為 SonFakePromise ,而先前調(diào)用 then 的對象為 FatherFakePromise

那么問題來了

那么構(gòu)造這個 SonFakePromise 的函數(shù)參數(shù)是什么

這個 SonFakePromise 什么時候 resolve ?

首先,當(dāng)構(gòu)造一個新的 SonFakePromise 時,會將傳入的函數(shù)參數(shù) fn 執(zhí)行一遍,且這個函數(shù)有 resolve 參數(shù)

...
    then(onFulfilled){
      if(this.state === "pending"){
        this.callbacks.push(onFulfilled)
        let SonFakePromise = new FakePromise(function fn(resolve){
          
        })
        return SonFakePromise
      }else{
        onFulfilled(this.value)
        let SonFakePromise = new FakePromise(function fn(resolve){
          
        })
        return SonFakePromise
      }
    }
...

現(xiàn)在的問題是這個 SonFakePromise 什么時候 resolve ?即構(gòu)造函數(shù)中的函數(shù)參數(shù) fn 如何定義

結(jié)合正經(jīng) Promise 的例子來看

let faherPromise = new Promise(resolve => {
    fs.readFile("./test.js", "utf8", (err, data) => {
        resolve(data)
    })
}).then(res => {
    return new Promise(resolve => {
        fs.readFile("./main.js", "utf8", (err, data) => {
            resolve(data)
        })
    })
}).then(res => {
    console.log(res)
})
// 等同于
let faherPromise = new Promise(resolve => {
    fs.readFile("./test.js", "utf8", (err, data) => {
        resolve(data)
    })
})
let sonPromise = faherPromise.then(function onFulfilled(res){
    return new Promise(function fn(resolve){
        fs.readFile("./main.js", "utf8", (err, data) => {
            resolve(data)
        })
    })
}).then(res => {
    console.log(res)
})

在例子中,onFulfilled 函數(shù)如下,且其執(zhí)行后返回一個新的 Promise,暫時取名為 fulPromise

function onFulfilled(res) {
  return new Promise(function fn(resolve){
    fs.readFile("./main.js", "utf8", (err, data) => {
      resolve(data)
    })
  })
}

現(xiàn)在來分析一下,fatherPromisesonPromisefulPromise 這三者的關(guān)系

sonPromise 是調(diào)用 fatherPromise 的 then 方法返回的

而調(diào)用這個 then 方法需要傳入一個函數(shù)參數(shù),取名為 retFulPromise

retFulPromise 函數(shù)執(zhí)行的返回值 fulPromise

希望下面的代碼能有助于理解

let fatherPromise = new Promise(function fatherFn(fatherResolve){
  fs.readFile("./test.js", "utf8", (err, data) => {
    fatherResolve(data)
  })
})

let sonPromise = fatherPromise.then(retFulPromise)

function retFulPromise(res) {
  let fulPromise = new Promise(function fulFn(fulResolve){
    fs.readFile("./main.js", "utf8", (err, data) => {
      fulResolve(data)
    })
  })
  return fulPromise
}

fatherPromise 的狀態(tài)為 fulfilled 時,會執(zhí)行 retFulPromise,其返回 fulPromise ,當(dāng)這個 fulPromise 執(zhí)行 fulResolve 時,即完成讀取 main.js 時, sonPromise 也會執(zhí)行內(nèi)部的 resolve

所以可以看成,sonPromise 的 sonResolve 函數(shù),也被注冊到了 fulPromise 上

So,了解了整個流程,該怎么修改自己的 FakePromise 呢?

秀操作,考驗技巧的時候到了,將 sonResolve 的引用保存起來,注冊到 fulFakePromise 上

const fs = require("fs")

class FakePromise {
    constructor(fn) {
        this.value = null
        this.state = "pending"
        this.callbacks = []
        resolve = resolve.bind(this)

        function resolve(value) {
            setTimeout(() => {
                this.value = value
                this.state = "fulfilled"
                this.callbacks.forEach(cb => {
                    let returnValue = cb.onFulfilled(value)
                    if (returnValue instanceof FakePromise) {
                        returnValue.then(cb.sonResolveRes)
                    }
                })
            })
        }
        fn(resolve)
    }

    then(onFulfilled) {
        if (this.state === "pending") {
            let sonResolveRes = null
            let sonFakePromise = new FakePromise(function sonFn(sonResolve) {
                sonResolveRes = sonResolve
            })
            this.callbacks.push({
                sonFakePromise,
                sonResolveRes,
                onFulfilled
            })
            return sonFakePromise
        } else {
            let value = onFulfilled(this.value)
            let sonResolveRes = null
            let sonFakePromise = new FakePromise(function sonFn(sonResolve) {
                sonResolveRes = sonResolve
            })
            if (value instanceof FakePromise) {
                value.then(sonResolveRes)
            }
            return sonFakePromise
        }
    }
}
多角度測試
let fatherFakePromise = new FakePromise(resolve => {
    fs.readFile("./test.js", "utf8", (err, data) => {
        resolve(data)
    })
})
let sonFakePromise = fatherFakePromise.then(function onFulfilled(res) {
    return new FakePromise(function fn(resolve) {
        fs.readFile("./main.js", "utf8", (err, data) => {
            resolve(data)
        })
    })
}).then(res => {
    console.log(res)
})
let fatherFakePromise = new FakePromise(resolve => {
    fs.readFile("./test.js", "utf8", (err, data) => {
        resolve(data)
    })
})
setTimeout(function () {
    let sonFakePromise = fatherFakePromise.then(function onFulfilled(res) {
        return new FakePromise(function fn(resolve) {
            fs.readFile("./main.js", "utf8", (err, data) => {
                resolve(data)
            })
        })
    }).then(res => {
        console.log(res)
    })
}, 1000)
let fatherFakePromise = new FakePromise(resolve => {
    resolve("haha")
})

let sonFakePromise = fatherFakePromise.then(function onFulfilled(res) {
    return new FakePromise(function fn(resolve) {
        fs.readFile("./main.js", "utf8", (err, data) => {
            resolve(data)
        })
    })
}).then(res => {
    console.log(res)
})
let fatherFakePromise = new FakePromise(resolve => {
    resolve("haha")
})

setTimeout(function () {
    let sonFakePromise = fatherFakePromise.then(function onFulfilled(res) {
        return new FakePromise(function fn(resolve) {
            fs.readFile("./main.js", "utf8", (err, data) => {
                resolve(data)
            })
        })
    }).then(res => {
        console.log(res)
    })
}, 1000)
參考資料

30分鐘,讓你徹底明白Promise原理

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/107249.html

相關(guān)文章

  • 歷史首次!聯(lián)發(fā)科打敗高通成為全球第一,憑什么?

    摘要:據(jù)調(diào)研機構(gòu)數(shù)據(jù),年第三季度,全球智能手機芯片市場占有率中,聯(lián)發(fā)科力壓高通,歷史首次登頂全球第一。年月,聯(lián)發(fā)科發(fā)布全球首款十核處理器,以及它的升級版。聯(lián)發(fā)科本月表示,其最新的旗艦芯片將于明年第一季度發(fā)布,希望在農(nóng)歷新年前推出。在被喊了一年的MTK YES后,聯(lián)發(fā)科終于迎來了自己的YES時刻。據(jù)調(diào)研機構(gòu)Counterpoint數(shù)據(jù),2020年第三季度,全球智能手機芯片市場占有率中,聯(lián)發(fā)科力壓高通...

    Tecode 評論0 收藏0
  • 原生JS模擬Bootstrap中的折疊(Collapse)插件

    摘要:以前實習(xí)的時候因為趕時間直接用的插件做了個折疊菜單,對于一個原生控來說還是更傾向于自己寫一個,畢竟為了個折疊菜單引入和有點太臃腫了。原版的效果其實也不難,主要是在開合的過程中添加了的過渡效果。 以前實習(xí)的時候因為趕時間直接用bootstrap的插件collapse.js做了個折疊菜單, 對于一個原生控來說還是更傾向于自己寫一個, 畢竟為了個折疊菜單引入jq和bootstrap有點太臃腫...

    IntMain 評論0 收藏0
  • 樂字節(jié)Java反射之一:反射概念與獲取反射源頭class

    摘要:一反射機制概念程序運行時,允許改變程序結(jié)構(gòu)或變量類型,這種語言稱為動態(tài)語言,如,是動態(tài)語言顯然,,不是動態(tài)語言,但是有著一個非常突出的動態(tài)相關(guān)機制。相關(guān)的為二獲取源頭重點打開權(quán)限所有類的對象其實都是的實例。 一、Java反射機制概念 程序運行時,允許改變程序結(jié)構(gòu)或變量類型,這種語言稱為動態(tài)語言,如Python, Ruby是動態(tài)語言;顯然C++,Java,C#不是動態(tài)語言,但是JAVA有...

    caikeal 評論0 收藏0
  • [phaser3入門探坑]使用phaser3制作山寨馬里奧

    摘要:前言是一個優(yōu)秀的前端庫,封裝了很多底層的實現(xiàn),可以用來制作游戲,場景等。今年月新發(fā)布了,到今天為止已經(jīng)更新到了。聲明本游戲來自于小站的官方教程,加入了一些個人的注釋,本文旨在幫助各位觀眾老爺快速上手。 前言 phaser是一個優(yōu)秀的前端canvas庫,封裝了很多底層的實現(xiàn),可以用來制作游戲,h5場景等。今年1月新發(fā)布了phaser3,到今天為止已經(jīng)更新到了3.30。 聲明 本游戲來自于...

    szysky 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<