国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

山寨一個(gè) Promise

XFLY / 2713人閱讀

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

一點(diǎn)感悟

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

相比 Callback ,它有以下特點(diǎn)

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

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

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

發(fā)起異步事件

處理異步結(jié)果

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

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 實(shí)現(xiàn)一樣的效果

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

待異步事件返回結(jié)果,再遍歷 callbacks ,依次執(zhí)行所有注冊(cè)的函數(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 有點(diǎn)像

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

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

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

延時(shí) resolve

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

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

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

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

但是 Promise 還有個(gè)額外的功能是在發(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 注冊(cè)處理事件,并且該事件會(huì)立即執(zhí)行

先發(fā)布,再訂閱

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

Promise 規(guī)范中采用的狀態(tài)機(jī)制是 pendingfulfilledrejected

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)
        }
    }
}

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

并不可以,因?yàn)槿思艺?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 實(shí)現(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 方法會(huì)返回一個(gè)新的 Promise 對(duì)象

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

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

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

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

那么問題來了

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

這個(gè) SonFakePromise 什么時(shí)候 resolve ?

首先,當(dāng)構(gòu)造一個(gè)新的 SonFakePromise 時(shí),會(huì)將傳入的函數(shù)參數(shù) fn 執(zhí)行一遍,且這個(gè)函數(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)在的問題是這個(gè) SonFakePromise 什么時(shí)候 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í)行后返回一個(gè)新的 Promise,暫時(shí)取名為 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)用這個(gè) then 方法需要傳入一個(gè)函數(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 時(shí),會(huì)執(zhí)行 retFulPromise,其返回 fulPromise ,當(dāng)這個(gè) fulPromise 執(zhí)行 fulResolve 時(shí),即完成讀取 main.js 時(shí), sonPromise 也會(huì)執(zhí)行內(nèi)部的 resolve

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

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

秀操作,考驗(yàn)技巧的時(shí)候到了,將 sonResolve 的引用保存起來,注冊(cè)到 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
        }
    }
}
多角度測(cè)試
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)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/107249.html

相關(guān)文章

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

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

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

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

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

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

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

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

    szysky 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<