亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專(zhuān)欄INFORMATION COLUMN

Promise 的then 里發(fā)生了什么

Joyven / 2627人閱讀

摘要:大家都知道怎么用,但是對(duì)于內(nèi)部的原理很多人都不是很清楚來(lái)看一個(gè)面試題的是怎么實(shí)現(xiàn)的首先來(lái)分析一下是屬于實(shí)例上的方法參數(shù)有個(gè),分別為,并且都是可選的可以實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用執(zhí)行要執(zhí)行或者方法參數(shù),分別有自己的參數(shù),分別是的參數(shù)跟的參數(shù)只能使用前一個(gè)的

Promise 大家都知道怎么用, 但是對(duì)于內(nèi)部的原理很多人都不是很清楚

來(lái)看一個(gè)面試題: Promise的then 是怎么實(shí)現(xiàn)的

首先來(lái)分析一下then

then是屬于實(shí)例上的方法

參數(shù)有2個(gè),分別為onFulfilled, onRejected,并且都是可選的

可以實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用

then執(zhí)行要執(zhí)行Promise onFulfilled 或者 onRejected 方法

參數(shù)onFulfilled,onRejected 分別有自己的參數(shù), 分別是resolve的參數(shù)跟reject的參數(shù)

then只能使用前一個(gè)then的返回值

then返回值不能是同一個(gè)promise

來(lái)一個(gè)一個(gè)看吧

then是屬于實(shí)例上的方法

Promise.prototype.then = function(){}

參數(shù)有2個(gè),分別為onFulfilled, onRejected,并且都是可選的

Promise.prototype.then = function(onFulfilled,onRejected){}

可以實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用

Promise.prototype.then = function(onFulfilled,onRejected){
    return new Promise(function(resolve,reject){
        // 代碼省略
    })
}

要實(shí)現(xiàn)promise鏈?zhǔn)? 返回的必須是一個(gè)Promise 再由于status 改變狀態(tài)了不能再變 所以需要第二個(gè).... 第N個(gè)promise 調(diào)用新的resolve

then執(zhí)行要執(zhí)行Promise onFulfilled 或者 onRejected 方法

Promise.prototype.then = function(onFulfilled,onRejected){
    var self = this; // 保存當(dāng)前上下文
    return new Promise(function(resolve,reject){
        if(self.status === "resolved"){
             onFulfilled(self.res)
        }
        if(self.status === "rejected"){
            onRejected(self.err)
        }
    })
}

Promise.resolve(res) 、、 同步代碼的執(zhí)行情況下 上述邏輯成立

參數(shù)onFulfilled,onRejected 分別有自己的參數(shù), 分別是resolve的參數(shù)跟reject的參數(shù)

res 跟err 來(lái)源如下

function Promise(executor){
    let self = this
    this.status = "pending"  // Promise 的狀態(tài)值
    this.res = undefined   // 存成功之后的值
    this.err = undefined   // 存失敗之后的值
    executor(resolve,reject)
    // 省略代碼
}

executor 有2個(gè)參數(shù) 分別為resolve,reject
當(dāng)調(diào)用

new Promise((resolve,reject)=>{
    setTimeout(()=>{
        if(true){
            resolve("res")
        }else{
            reject("err")
        }
       
    },1000)
})

executor 會(huì)執(zhí)行 并且把成功的值或者失敗的值拋出來(lái),resolve跟reject也是2個(gè)函數(shù) 定義在Promise內(nèi)部

function Promise(executor){
     // ...代碼省略
    function resolve(res){
        self.res = res 
    }
    function reject(err){
        self.err = err 
    }
    executor(resolve,reject)
    
}

resolve 跟reject 還需要改變 Promise的狀態(tài)值 并且一旦發(fā)生改變之后不能再次改變

function Promise(executor){
    // 代碼省略
    function resolve(res){
        if(self.status === "pending"){
            self.status = "resolved"
            self.res = res 
        }
    }
    function reject(err){
        if(self.status === "pending"){
            self.status = "rejected"
            self.err = err 
        }
    }
    executor(resolve,reject)
}

我們?cè)趀xecutor中操作的往往是異步代碼, 這個(gè)之后直接then, status的狀態(tài)值并未發(fā)生改變, 所以不會(huì)執(zhí)行onFulfilled跟onRejected,
這個(gè)時(shí)候我們需要訂閱

function Promise(executor){
    // 代碼省略
    this.onFulfilledCallback = []  // 存成功之后的回調(diào)
    this.onrejectedCallback = []  // 存失敗之后的回調(diào)
    function resolve(res){
        if(self.status === "pending"){
            self.status = "resolved"
            self.res = res 
        }
    }
    function reject(err){
        if(self.status === "pending"){
            self.status = "rejected"
            self.err = err 
        }
    }
    executor(resolve,reject)
}

new Promise(executor).then((onFulfilled,onrejected)=>{
    var self = this; // 保存當(dāng)前上下文   **注意: 第二次調(diào)用then this是指向new Promise的**
    return new Promise(function(resolve,reject){
        // ...代碼省略
        if(self.status === "pending"){
            self.onFulfilledCallback.push(function(){   // 把成功之后需要做的事存起來(lái)  有多少個(gè)then就有多少個(gè)函數(shù)
                onFulfilled(self.res)   // 注意 這里的self.res 會(huì)隨著then的調(diào)用發(fā)生改變  因?yàn)槊看蝨hen都new 了一個(gè)Promise
            })
            self.onrejectedCallback.push(function(){   // 把失敗之后的事存起來(lái) 有多少個(gè)then就有多少個(gè)函數(shù)
                onFulfilled(self.err)
            })
        }
    })
})

當(dāng)resolve的時(shí)候 或者reject的時(shí)候
一一拿出來(lái)執(zhí)行

function resolve(res){
    // 省略代碼
    self.res = res
    onFulfilledCallback.forEach(fn=>{
        fn()
    })
}

實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用我們需要對(duì)then函數(shù)執(zhí)行的返回值做一個(gè)操作?。?!

需求:

then的參數(shù)onFulfilled函數(shù) 需要接收到上一個(gè)onfulfilled的執(zhí)行結(jié)果

Promise.prototype.then = function(onFulfilled,onRejected){
    return new Promise((resolve,reject)=>{
        // ...代碼省略
        if(self.status === "resolved"){
            let x = onFulfilled(self.res)   // 拿到onFulfilled的執(zhí)行結(jié)果  注意:這里執(zhí)行Promise.resolve() 同步代碼
            // 然后把x傳遞給下一個(gè)then
            resolve(x)
        }
    })
}

如果resolve是異步的話(huà)

Promise.prototype.then = function(onFulfilled,onRejected){
    return new Promise((resolve,reject)=>{
        // ...代碼省略
        if(self.status === "resolved"){
            let x = onFulfilled(self.res)   // 拿到onFulfilled的執(zhí)行結(jié)果  注意:這里執(zhí)行的是Promise.resolve() 同步代碼
            // 然后把x傳遞給下一個(gè)then
            resolve(x)
        }
        if(self.status === "pending"){
            self.onFulfilledCallback.push(function(){
                let x = onFulfilled(self.res)  // 這里的self.res 是上一個(gè)new Promise上的值 此時(shí)的onFUlfilled 相當(dāng)于 fn(){let x = onFulfilled}  
                resolve(x)
            })
        }
    })
}

//  同時(shí)為了拿到 fn(){let x = onFulfilled ...} 得值 傳遞給下一個(gè)onFulfilled,onFulfilledCallback需要改寫(xiě) onRejectedCallback同理

onFulfilledCallback.forEach(fn=>{
    return fn()
})
onRejectedCallback.forEach(fn=>{
    return fn()
})

-

onFullfillled 的返回值可能是個(gè)promise 也可能是個(gè)普通值

考慮如下情況:

1. 返回值是個(gè)promise

Promsie.resolve(11).then(res=>{

    return new Promise(executor) 
})

2. 返回值是個(gè)普通值

Promsie.resolve(11).then(res=>{

    return 1
})

最關(guān)鍵的來(lái)了
我們需要對(duì)onFullfillled 的返回值進(jìn)行判斷

修改then函數(shù)

// ...代碼省略
if(self.status === "resolved"){
        let x = onFulfilled(self.res)   // 拿到onFulfilled的執(zhí)行結(jié)果  注意:這里執(zhí)行的是Promise.resolve() 同步代碼
        // 然后把x傳遞給下一個(gè)then
        promiseResolve(x,resolve,reject)
        
    }
function promiseResolve(x,resolve,reject){
    if((typeof x != null && typeof x == "object") || typeof x == "function"){  // 確定是個(gè)引用類(lèi)型
        if (x instanceof Promise){  // 確定是個(gè)Promise 實(shí)例
            let then = x.then
            then.call(x,res=>{    //  保證x調(diào)用res=>{}, res=>{}是then的onFulfilled方法  一直判斷直到onFulfilled 返回的是個(gè)普通值 然后resolve出去
                promiseResolve(res,resolve,reject)
            },err=>{
                reject(err)
            })
        }
    }else{
        resolve(x)
    }
}

then返回值不能是同一個(gè)promise

考慮這樣極端問(wèn)題:

let p = new Promise(resolve=>{
    resolve(3333)
})

let p2 = p.then(resolve=>{
    return p2
})

這樣會(huì)出現(xiàn)什么問(wèn)題呢, onFulfilled的返回結(jié)果如果是一個(gè)promise 上面的遞歸調(diào)用已經(jīng)說(shuō)明了 我們要不斷的去遞歸最終的onFulfilled結(jié)果 然后再改變p2的status 這樣變成了p2去等待p2的執(zhí)行結(jié)果 函數(shù)死掉了

所以onFulfilled的返回結(jié)果需要跟then的返回結(jié)果去比較 修改函數(shù)

function promiseResolve(x,resolve,reject,promise){
    if(x === promise ){
        return new Error("引用錯(cuò)誤!")
    }
    if((typeof x != null && typeof x == "object") || typeof x == "function"){  // 確定是個(gè)引用類(lèi)型
        if (x instanceof Promise){  // 確定是個(gè)Promise 實(shí)例
            let then = x.then
            then.call(x,res=>{    //  保證x調(diào)用res=>{}, res=>{}是then的onFulfilled方法  一直判斷直到onFulfilled 返回的是個(gè)普通值 然后resolve出去
                promiseResolve(res,resolve,reject)
            },err=>{
                reject(err)
            })
        }
    }else{
        resolve(x)
    }
}
Promise.prototype.then = function(onFulfilled,onRejected){

    // ...代碼省略
    let promise2 = new Promise((resolve,reject)=>{
        if(self.status === "pending"){
            self.onFulfilledCallback.push(function(){
                let x = onFulfilled(self.res)  // 這里的self.res 是上一個(gè)new Promise上的值 此時(shí)的onFUlfilled 相當(dāng)于 fn(){let x = onFulfilled}  
                promiseResolve(x,resolve,reject,promise2)
            })
        }
    })
    return promise2
}

這段代碼還是有錯(cuò)誤, 由于javascript主線(xiàn)程是單線(xiàn)程的, 所以在then里的promiseResolve是拿不到promise2的 所以我們需要開(kāi)啟異步 使用定時(shí)器或者nextTick 這里我們用定時(shí)器

Promise.prototype.then = function(onFulfilled,onRejected){

    // ...代碼省略
    let promise2 = new Promise((resolve,reject)=>{
        if(self.status === "pending"){
            self.onFulfilledCallback.push(function(){
                setTimeout(()=>{
                    let x = onFulfilled(self.res)  // 這里的self.res 是上一個(gè)new Promise上的值 此時(shí)的onFUlfilled 相當(dāng)于 fn(){let x = onFulfilled}  
                    promiseResolve(x,resolve,reject,promise2)
                },0)
            })
        }
    })
    return promise2
}

此時(shí) 整個(gè)then差不多完成了

需要補(bǔ)充的點(diǎn)

onFulfilled,onRejected 有可能是undefined 這里未做判斷

在new Promise 時(shí) executor函數(shù)內(nèi)部有可能報(bào)錯(cuò) 這里未使用try catch捕獲

這里對(duì)于onRejected的錯(cuò)誤未拋出

總結(jié)

then每次創(chuàng)建一個(gè)新的promise對(duì)象 對(duì)于同步的resolve,reject直接調(diào)用onFulfilled或者onRejected ,對(duì)于異步的resolve,reject使用
訂閱發(fā)布模式,把每個(gè)resolve,reject 暫存起來(lái) 等達(dá)到條件時(shí)候一一執(zhí)行, 并且拿到返回結(jié)果去跟內(nèi)部的promise比較,并且判斷如果是一個(gè)promise的話(huà),不斷解析onFulfilled 的返回結(jié)果 直至resolve出去

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/102006.html

相關(guān)文章

  • ES6 Promise - Promise生命周期和創(chuàng)建

    摘要:通過(guò)構(gòu)造函數(shù),可以創(chuàng)建一個(gè)。函數(shù)本身是一個(gè)異步行為,其方法的第三個(gè)參數(shù)為一個(gè)回調(diào)函數(shù),用來(lái)接收文件讀取的結(jié)果失敗時(shí)候的和成功時(shí)候的。第一個(gè)函數(shù)的參數(shù)對(duì)應(yīng)的參數(shù),第二個(gè)回調(diào)函數(shù)對(duì)應(yīng)的參數(shù)。 一:Promise的概念 Promise的中文意思是‘承諾’,什么叫承諾?承諾就是現(xiàn)在沒(méi)有發(fā)生,在將來(lái)的某個(gè)時(shí)刻一定會(huì)發(fā)生的事情。放在編程語(yǔ)言的環(huán)境下,Promise就是異步事件的結(jié)果的占位符。我們不...

    Hydrogen 評(píng)論0 收藏0
  • 原創(chuàng) | JS異步工具之--Promise

    摘要:作者珂珂滬江前端開(kāi)發(fā)工程師本文為原創(chuàng)文章,有不當(dāng)之處歡迎指出。只對(duì)未來(lái)發(fā)生的事情做出兩種基本情況的應(yīng)對(duì)成功和失敗。在異步轉(zhuǎn)同步這條道路上,只是一個(gè)出彩的點(diǎn),他還尚有一些缺陷和不足,并不是我們最終的解決方案。 作者:珂珂 (滬江前端開(kāi)發(fā)工程師)本文為原創(chuàng)文章,有不當(dāng)之處歡迎指出。轉(zhuǎn)載請(qǐng)標(biāo)明出處。 一個(gè)新事物的產(chǎn)生必然是有其歷史原因的。為了更好的以同步的方式寫(xiě)異步的代碼,人們?cè)贘S上操碎了...

    alanoddsoff 評(píng)論0 收藏0
  • 馬蹄疾 | 詳解 JavaScript 異步機(jī)制及發(fā)展歷程(萬(wàn)字長(zhǎng)文)

    摘要:本文從入手,系統(tǒng)的回顧的異步機(jī)制及發(fā)展歷程。需要提醒的是,文本沒(méi)有討論的異步機(jī)制。這就是之前提到的事件觸發(fā)線(xiàn)程。其實(shí)無(wú)論是請(qǐng)求還是定時(shí)器還是事件,我們都可以統(tǒng)稱(chēng)它們?yōu)槭录?。第二階段,引擎線(xiàn)程專(zhuān)注于處理事件。將外元素的事件回調(diào)放入調(diào)用棧。 functionshowImg(url){ varframeid=frameimg+Math.random(); window.img=window....

    shaonbean 評(píng)論0 收藏0
  • 寫(xiě)一個(gè)符合promiseA+規(guī)范promise實(shí)現(xiàn)

    摘要:如何寫(xiě)一個(gè)符合規(guī)范的實(shí)現(xiàn)前言是異步編程的一種解決方案從語(yǔ)法上講,是一個(gè)對(duì)象,從它可以獲取異步操作的消息從本意上講,它是承諾,承諾它過(guò)一段時(shí)間會(huì)給你一個(gè)結(jié)果。 如何寫(xiě)一個(gè)符合promiseA+規(guī)范的promise實(shí)現(xiàn) 前言 Promise 是異步編程的一種解決方案:從語(yǔ)法上講,promise是一個(gè)對(duì)象,從它可以獲取異步操作的消息;從本意上講,它是承諾,承諾它過(guò)一段時(shí)間會(huì)給你一個(gè)結(jié)果。pr...

    hatlonely 評(píng)論0 收藏0
  • Promise初級(jí)與進(jìn)階---都在這

    摘要:處理和前一個(gè)回調(diào)函數(shù)運(yùn)行時(shí)發(fā)生的錯(cuò)誤發(fā)生錯(cuò)誤對(duì)象的錯(cuò)誤具有冒泡性質(zhì),會(huì)一直向后傳遞,直到被捕獲為止。 0 前言 我一直以為我對(duì)Promise比較了解,相關(guān)的方法已經(jīng)非常熟悉了,直到我看到這篇文章,里面提出了這樣一個(gè)問(wèn)題:Q: 假定 doSomething() 和 doSomethingElse() 均返回 promises,下面的四種 promises 的區(qū)別是什么 /...

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

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

0條評(píng)論

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