成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

性感的Promise,擁抱ta然后扒光ta

xushaojieaaa / 2451人閱讀

摘要:,異步編程的流行解決方案,相比于古老的回調(diào)函數(shù)等方式,它更科學(xué),更優(yōu)雅。它來自民間,后被官方招安。實(shí)現(xiàn)方法,方法和狀態(tài)機(jī)制根據(jù)使用方法我們可以知道,是一個(gè)需要接受一個(gè)執(zhí)行器的構(gòu)造函數(shù),執(zhí)行器提供兩個(gè)方法,內(nèi)部有狀態(tài)機(jī)制,原型鏈上有方法。

Promise,js異步編程的流行解決方案,相比于古老的回調(diào)函數(shù)等方式,它更科學(xué),更優(yōu)雅。它來自民間,后被官方招安。 本文將從介紹用法開始,一步步了解Promise,探究源碼,最終根據(jù)官方規(guī)范手寫一個(gè)Promise。 讓我們先擁抱ta,再扒光ta!
我想在你身上,做春天在櫻桃樹身上做的事情。——巴勃羅·聶魯達(dá)
1. How Promise?

創(chuàng)建Promise

首先來看看promise的用法,從名字可以看出它是個(gè)構(gòu)造函數(shù),所以我們得new它,得到一個(gè)Promise實(shí)例p,我們打印p看看

let p = new Promise
console.log(p) // TypeError: Promise resolver undefined is not a function

參數(shù)

報(bào)錯(cuò)信息告訴我們,Promise需要一些參數(shù),這里需要一個(gè)函數(shù)(我們叫它執(zhí)行器)作為參數(shù),該函數(shù)有兩個(gè)參數(shù)————resolve和reject,這兩個(gè)參數(shù)也是函數(shù)(由js引擎提供),我們可以在Promise內(nèi)部調(diào)用,當(dāng)異步操作成功時(shí),調(diào)用resolve,否則reject。

let p =new Promise(function(resolve, reject){
    if(/* 異步操作成功 */){
        resolve(data)
    }else{
        reject(err)
    }
})

state

現(xiàn)在我們需要知道一個(gè)重要概念,Promise是有“狀態(tài)”的,分別是pending(等待態(tài))、fulfilled(成功態(tài))、rejected(失敗態(tài)),pending可以轉(zhuǎn)換為fulfilled或rejected,但fulfilled和rejected不可相互轉(zhuǎn)化。

resolve/reject 方法

resolve方法可以將pending轉(zhuǎn)為fulfilled,reject方法可以將pending轉(zhuǎn)為rejected。

then方法

通過給Promise示例上的then方法傳遞兩個(gè)函數(shù)作為參數(shù),可以提供改變狀態(tài)時(shí)的回調(diào),第一個(gè)函數(shù)是成功的回調(diào),第二個(gè)則是失敗的回調(diào)。

p.then(function(data){ // resolve方法會(huì)將參數(shù)傳進(jìn)成功的回調(diào)
    console.log(data)  
}, function(err){      // reject方法會(huì)將失敗的信息傳進(jìn)失敗的回調(diào)
    console.log(err)
})


舉個(gè)栗子

let p = new Promise(function(resolve, reject){
    setTimeout(function(){
        let num = Math.random()
        if (num > 0.5) {
            resolve(num)
        }else{
            reject(num)
        }
    }, 1000)
})
p.then(function(num){
    console.log("大于0.5的數(shù)字:", num)
},function(num){
    console.log("小于等于0.5的數(shù)字", num)
})
// 運(yùn)行第一次:小于等于0.5的數(shù)字 0.166162996031475
// 運(yùn)行第二次:大于0.5的數(shù)字: 0.6591451548308984
...

在Promise執(zhí)行器中我們進(jìn)行了一次異步操作,并在我們覺得合適的時(shí)候調(diào)用成功或失敗的回調(diào)函數(shù),并拿到了想要的數(shù)據(jù)以進(jìn)行下一步操作

鏈?zhǔn)秸{(diào)用

除此之外,每一個(gè)then方法都會(huì)返回一個(gè)新的Promise實(shí)例(不是原來那個(gè)),讓then方法支持鏈?zhǔn)秸{(diào)用,并可以通過返回值將參數(shù)傳遞給下一個(gè)then

p.then(function(num){
    return num
},function(num){
    return num
}).then(function(num){
    console.log("大于0.5的數(shù)字:", num)
},function(num){
    console.log("小于等于0.5的數(shù)字", num)
})

catch方法

catch方法等同于.then(null, rejection),可以直接指定失敗的回調(diào)(支持接收上一個(gè)then發(fā)生的錯(cuò)誤)

Promise.all()

這可能是個(gè)很有用的方法,它可以統(tǒng)一處理多個(gè)Promise

Promise.all能將多個(gè)Promise實(shí)例包裝成一個(gè)Promise實(shí)例

let Promise1 = new Promise(function(resolve, reject){})
let Promise2 = new Promise(function(resolve, reject){})
let Promise3 = new Promise(function(resolve, reject){})

let p = Promise.all([Promise1, Promise2, Promise3])

p.then(funciton(){
  // 三個(gè)都成功則成功  
}, function(){
  // 只要有失敗,則失敗 
})

這個(gè)組合后的Promise實(shí)例和普通實(shí)例一樣,有三種狀態(tài),這里有組成它的幾個(gè)小Promise的狀態(tài)決定

1、當(dāng)Promise1, Promise2, Promise3的狀態(tài)都為成功態(tài),則p為成功態(tài);
2、當(dāng)Promise1, Promise2, Promise3中有任意一個(gè)為失敗態(tài),則p為失敗態(tài);

Promise.race()

與all方法類似,也可以講多個(gè)Promise實(shí)例包裝成一個(gè)新的Promise實(shí)例

不同的是,all時(shí)大Promise的狀態(tài)由多個(gè)小Promise共同決定,而race時(shí)由第一個(gè)轉(zhuǎn)變狀態(tài)的小Promise的狀態(tài)決定,第一個(gè)是成功態(tài),則轉(zhuǎn)成功態(tài),第一個(gè)失敗態(tài),則轉(zhuǎn)失敗態(tài)

Promise.resolve()

可以生成一個(gè)成功的Promise

Promise.resolve("成功")等同于new Promise(function(resolve){resolve("成功")})

Promise.resolve()

可以生成一個(gè)失敗的Promise

Promise.reject("出錯(cuò)了")等同于new Promise((resolve, reject) => reject("出錯(cuò)了"))

上述用法不夠詳細(xì),下面的代碼會(huì)更容易理解 2. Why Promise?

以jquery的ajax為例(@1.5.0版本以前,后來jqery也引入了Promise的概念),看看從前我們是如何解決異步問題的。

$.get("url", {data: data}, function(result){
    console.log("成功", result)// 成功的回調(diào),result為異步拿到的數(shù)據(jù)
});

看起來還可以?

想象一個(gè)場景,當(dāng)我們需要發(fā)送多個(gè)異步請求,而請求之間相互關(guān)聯(lián)相互依賴,沒有請求1就不會(huì)有請求2,沒有請求2就不會(huì)有請求3........

這時(shí)我們需要這樣寫

$.get("url", {data: data}, function(result1){
    $.get("url", {data: result1}, function(result2){
        $.get("url", {data: result2}, function(result3){
            $.get("url", {data: result3}, function(result4){
                ......
                $.get("url", {data: resultn}, function(resultn+1){
                    console.log("成功")
                }
            }
        }
    }
});

這樣的話,我們就掉入了傳說中的回調(diào)地獄,萬劫不復(fù),不能自拔。

這種代碼,難以維護(hù)和調(diào)試,一旦出現(xiàn)bug,牽一發(fā)而動(dòng)全身。

下面我們看看Promise是如何解決的,我們以node中的fs訪問文件舉例

先創(chuàng)建三個(gè)相互依賴的txt文件

1.txt的內(nèi)容:

2.txt

2.txt的內(nèi)容:

3.txt

3.txt的內(nèi)容:

完成

js代碼:

let readFile = require("fs").readFile; // 加載node內(nèi)置模塊fs 利用readFile方法異步訪問文件
function getFile(url){  // 創(chuàng)建一個(gè)讀取文件方法
    return new Promise(function(resolve, reject){  // 返回一個(gè)Promise對象
        readFile(url, "utf8", function(err,data){  // 讀取文件  
            resolve(data)  // 調(diào)用成功的方法
        })
    })
}
getFile("1.txt").then(function(data){  // then方法進(jìn)行鏈?zhǔn)秸{(diào)用
    console.log(data)  // 2.txt
    return getFile(data)    //拿到了第一次的內(nèi)容用來請求第二次
}).then(function(data){
    console.log(data)  // 3.txt
    return getFile(data)  //拿到了第二次的內(nèi)容用來請求第三次
}).then(function(data){
    console.log(data)  // 完成
})

(這里我們先不必搞懂代碼,下面會(huì)介紹具體用法)

看起來多了幾行代碼[尷尬],但我們通過創(chuàng)建一個(gè)讀取函數(shù)返回一個(gè)Promise對象,再利用Promise自帶的.then方法,將嵌套的異步代碼弄得看起來像同步一樣,這樣的話,出現(xiàn)問題可以輕易的調(diào)試和修改。

3. What Promise?

接下來是本文的重頭戲,根據(jù)PromiseA+(Promise的官方標(biāo)準(zhǔn))動(dòng)手實(shí)現(xiàn)一個(gè)180行左右代碼的promise,功能可實(shí)現(xiàn)多數(shù)(then catch all race resolve reject),這里會(huì)將的比較詳細(xì),一步一步理清思路。

實(shí)現(xiàn)resolve、reject方法,then方法和狀態(tài)機(jī)制

根據(jù)使用方法我們可以知道,Promise是一個(gè)需要接受一個(gè)執(zhí)行器的構(gòu)造函數(shù),執(zhí)行器提供兩個(gè)方法,內(nèi)部有狀態(tài)機(jī)制,原型鏈上有then方法。

開始擼:

// myPromise
function Promise(executor){ //executor是一個(gè)執(zhí)行器(函數(shù))
    let _this = this // 先緩存this以免后面指針混亂
    _this.status = "pending" // 默認(rèn)狀態(tài)為等待態(tài)
    _this.value = undefined // 成功時(shí)要傳遞給成功回調(diào)的數(shù)據(jù),默認(rèn)undefined
    _this.reason = undefined // 失敗時(shí)要傳遞給失敗回調(diào)的原因,默認(rèn)undefined
    function resolve(value) { // 內(nèi)置一個(gè)resolve方法,接收成功狀態(tài)數(shù)據(jù)
        // 上面說了,只有pending可以轉(zhuǎn)為其他狀態(tài),所以這里要判斷一下
        if (_this.status === "pending") { 
            _this.status = "resolved" // 當(dāng)調(diào)用resolve時(shí)要將狀態(tài)改為成功態(tài)
            _this.value = value // 保存成功時(shí)傳進(jìn)來的數(shù)據(jù)
        }
    }
    function reject(reason) { // 內(nèi)置一個(gè)reject方法,失敗狀態(tài)時(shí)接收原因
        if (_this.status === "pending") { // 和resolve同理
            _this.status = "rejected" // 轉(zhuǎn)為失敗態(tài)
            _this.reason = reason // 保存失敗原因
        }
    }
    executor(resolve, reject) // 執(zhí)行執(zhí)行器函數(shù),并將兩個(gè)方法傳入
}
// then方法接收兩個(gè)參數(shù),分別是成功和失敗的回調(diào),這里我們命名為onFulfilled和onRjected
Promise.prototype.then = function(onFulfilled, onRjected){
    let _this = this;   // 依然緩存this
    if(_this.status === "resolved"){  // 判斷當(dāng)前Promise的狀態(tài)
        onFulfilled(_this.value)  // 如果是成功態(tài),當(dāng)然是要執(zhí)行用戶傳遞的成功回調(diào),并把數(shù)據(jù)傳進(jìn)去
    }
    if(_this.status === "rejected"){ // 同理
        onRjected(_this.reason)
    }
}
module.exports = Promise  // 導(dǎo)出模塊,否則別的文件沒法使用

注意:上面代碼的命名不是隨便起的,像onFulfilled和onRjected,是嚴(yán)格按照Promise/A+規(guī)范走的,不信你看圖

這樣我們就實(shí)現(xiàn)了第一步,可以創(chuàng)建Promise實(shí)例并使用then方法了,測試一下

let Promise = require("./myPromise")  // 引入模塊
let p = new Promise(function(resolve, reject){
  resolve("test")
})
p.then(function(data){
  console.log("成功", data)
},function(err){
  console.log("失敗", err)
})
// 成功 test

再試試reject

let Promise = require("./myPromise")  // 引入模塊
let p = new Promise(function(resolve, reject){
  reject("test")
})
p.then(function(data){
  console.log("成功", data)
},function(err){
  console.log("失敗", err)
})
// 失敗 test

看起來不錯(cuò),但回調(diào)函數(shù)是立即執(zhí)行的,無法進(jìn)行異步操作,比如這樣是不行的

let p = new Promise(function(resolve, reject){
  setTimeout(function(){
    resolve(100)  
  }, 1000)
})
p.then(function(data){
  console.log("成功", data)
},function(err){
  console.log("失敗", err)
})
// 不會(huì)輸出任何代碼

原因是我們在then函數(shù)中只對成功態(tài)和失敗態(tài)進(jìn)行了判斷,而實(shí)例被new時(shí),執(zhí)行器中的代碼會(huì)立即執(zhí)行,但setTimeout中的代碼將稍后執(zhí)行,也就是說,then方法執(zhí)行時(shí),Promise的狀態(tài)沒有被改變依然是pending態(tài),所以我們要對pending態(tài)也做判斷,而由于代碼可能是異步的,那么我們就要想辦法把回調(diào)函數(shù)進(jìn)行緩存,并且,then方法是可以多次使用的,所以要能存多個(gè)回調(diào),那么這里我們用一個(gè)數(shù)組。

實(shí)現(xiàn)異步

在實(shí)例上掛兩個(gè)參數(shù)

_this.onResolvedCallbacks = []; // 存放then成功的回調(diào)
_this.onRejectedCallbacks = []; // 存放then失敗的回調(diào)

then方法加一個(gè)pending時(shí)的判斷

if(_this.status === "pending"){
    // 每一次then時(shí),如果是等待態(tài),就把回調(diào)函數(shù)push進(jìn)數(shù)組中,什么時(shí)候改變狀態(tài)什么時(shí)候再執(zhí)行
    _this.onResolvedCallbacks.push(function(){ // 這里用一個(gè)函數(shù)包起來,是為了后面加入新的邏輯進(jìn)去
        onFulfilled(_this.value)
    })
    _this.onRejectedCallbacks.push(function(){ // 同理
        onRjected(_this.reason)
    })
}

下一步要分別在resolve和reject方法里加入執(zhí)行數(shù)組中存放的函數(shù)的方法,修改一下上面的resolve和reject方法

function resolve(value) {
    if (_this.status === "pending") { 
        _this.status = "resolved"
        _this.value = value
        _this.onResolvedCallbacks.forEach(function(fn){ // 當(dāng)成功的函數(shù)被調(diào)用時(shí),之前緩存的回調(diào)函數(shù)會(huì)被一一調(diào)用
            fn()
        })
    }
}
function reject(reason) {
    if (_this.status === "pending") {
        _this.status = "rejected"
        _this.reason = reason
        _this.onRejectedCallbacks.forEach(function(fn){// 當(dāng)失敗的函數(shù)被調(diào)用時(shí),之前緩存的回調(diào)函數(shù)會(huì)被一一調(diào)用
            fn()
        })
    }
}

現(xiàn)在可以執(zhí)行異步任務(wù)了,也可以多次then了,一個(gè)窮人版Promise就完成了,

處理錯(cuò)誤

上面的代碼雖然能用,但經(jīng)不起考驗(yàn),真正的Promise如果在實(shí)例中拋出錯(cuò)誤,應(yīng)該走reject:

new Promise(function(resolve, reject){
  throw new Error("錯(cuò)誤")
}).then(function(){
    
},function(err){
  console.log("錯(cuò)誤:", err)  
})
// 錯(cuò)誤: Error: 錯(cuò)誤

我們實(shí)現(xiàn)一下,思路很簡單,在執(zhí)行器執(zhí)行時(shí)進(jìn)行thy catch

try{
    executor(resolve, reject)        
}catch(e){ // 如果捕獲發(fā)生異常,直接調(diào)失敗,并把參數(shù)穿進(jìn)去
    reject(e)
}

實(shí)現(xiàn)then的鏈?zhǔn)秸{(diào)用(難點(diǎn))

上面說過了,then可以鏈?zhǔn)秸{(diào)用,也是這一點(diǎn)讓Promise十分好用,當(dāng)然這部分源碼也比較復(fù)雜

我們知道jquery實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用是return了一個(gè)this,但Promise不行,為什么不行?

正宗的Promise是這樣的套路:

let p1 = new Promise(function(resolve, reject){
  resolve()
})
let p2 = p1.then(function(data){ //這是p1的成功回調(diào),此時(shí)p1是成功態(tài)
    throw new Error("錯(cuò)誤") // 如果這里拋出錯(cuò)誤,p2應(yīng)是失敗態(tài)
})
p2.then(function(){
    
},function(err){
    console.log(err)
})
// Error: 錯(cuò)誤

如果返回的是this,那么p2跟p1相同,固狀態(tài)也相同,但上面說了,Promise的成功態(tài)和失敗態(tài)不能相互轉(zhuǎn)換,那就不會(huì)得到p1成功而p2失敗的效果,而實(shí)際上是可能發(fā)生這種情況的。

所以Promise的then方法實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用的原理是:返回一個(gè)新的Promise

在then方法中先定義一個(gè)新的Promise,取名為promise2(官方規(guī)定的),然后在三種狀態(tài)下分別用promise2包裝一下,在調(diào)用onFulfilled時(shí)用一個(gè)變量x(規(guī)定的)接收返回值,trycatch一下代碼,沒錯(cuò)就調(diào)resolve傳入x,有錯(cuò)就調(diào)reject傳入錯(cuò)誤,最后再把promise2給return出去,就可以進(jìn)行鏈?zhǔn)秸{(diào)用了,,,,但是!

// 改動(dòng)then
let promise2;
if (_this.status === "resolved") {
    promise2 = new Promise(function (resolve, reject) {
        // 可以湊合用,但是是有很多問題的
        try { 
            let x = onFulfilled(_this.value)
            resolve(x)
        } catch (e) {
            reject(e)
        }
    })
}
if (_this.status === "rejected") {
    promise2 = new Promise(function (resolve, reject) {
        // 可以湊合用,但是是有很多問題的
        try {
            let x = onRjected(_this.reason)
            resolve(x)
        } catch (e) {
            reject(e)
        }
    })
}
if(_this.status === "pending"){
    promise2 = new Promise(function (resolve, rejec
        _this.onResolvedCallbacks.push(function(){
             // 可以湊合用,但是是有很多問題的
            try {
                let x = onFulfilled(_this.value)
                resolve(x)
            } catch (e) {
                reject(e)
            }
        })
        _this.onRejectedCallbacks.push(function(){
             // 可以湊合用,但是是有很多問題的
            try {
                let x = onRjected(_this.reason)
                resolve(x)
            } catch (e) {
                reject(e)
            }
        })
    })
}
return promise2

這里我先解釋一下x的作用再說為什么不行,x是用來接收上一次then的返回值,比如這樣

let p = new Promise(function(resolve, reject){
  resolve(data)  
})
p.then(function(data){
    return xxx // 這里返回一個(gè)值
}, function(){
    
}).then(function(data){
    console.log // 這里會(huì)接收到xxx
}, function(){
    
})
// 以上代碼中第一次then的返回值就是源碼內(nèi)第一次調(diào)用onRjected的返回值,可以用一個(gè)x來接收

接下來說問題,上面這樣看起來是符合邏輯的,并且也確實(shí)可以鏈?zhǔn)秸{(diào)用并接受到,但我們在寫庫,庫就要經(jīng)得起考驗(yàn),把容錯(cuò)性提到最高,要接受使用者各種新(cao)奇(dan)操作,所謂有容nai大。可能性如下:

1、前一次then返回一個(gè)普通值,字符串?dāng)?shù)組對象這些東西,都沒問題,只需傳給下一個(gè)then,剛才的方法就夠用。

2、前一次then返回的是一個(gè)Promise,是正常的操作,也是Promise提供的語法糖,我們要想辦法判斷到底返回的是啥。

3、前一次then返回的是一個(gè)Promise,其中有異步操作,也是理所當(dāng)然的,那我們就要等待他的狀態(tài)改變,再進(jìn)行下面的處理。

4、前一次then返回的是自己本身這個(gè)Promise

var p1 = p.then(function(){// 這里得用var,let由于作用域的原因會(huì)報(bào)錯(cuò)undefined
  return p1  
})

5、前一次then返回的是一個(gè)別人自己隨便寫的Promise,這個(gè)Promise可能是個(gè)有then的普通對象,比如{then:"哈哈哈"},也有可能在then里故意拋錯(cuò)(這種蛋疼的操作我們也要考慮進(jìn)去)。比如他這樣寫

let promise = {}
Object.defineProperty(promise,"then",{
    value: function(){
        throw new Error("報(bào)錯(cuò)氣死你")
    }
})
// 如果返回這東西,我們再去調(diào)then方法就肯定會(huì)報(bào)錯(cuò)了

6、調(diào)resolve的時(shí)候再傳一個(gè)Promise下去,我們還得處理這個(gè)Promise。

p.then(function(data) {
    return new Promise(function(resolve, reject) {
      resolve(new Promise(function(resolve,reject){
        resolve(1111)
      }))
    })
})

7、可能既調(diào)resolve又調(diào)reject,得忽略后一個(gè)。

8、光then,里面啥也不寫。

。。

稍等,我先吐一會(huì)。。。

好了咱們調(diào)整心情繼續(xù)擼,其實(shí)這一系列的問題,很多都是相關(guān)的,只要根據(jù)規(guī)范,都可以順利解決,接上面的代碼,先干三件事

1、問題7是最好解決的,如果沒傳resolve和reject,我們就給他一個(gè)。

2、官方規(guī)范規(guī)定了一件事

簡單說就是為免在測試中出問題onFulfilled和onRejected要異步執(zhí)行,我們就讓他異步執(zhí)行

3、問題1-7,我們可以采取統(tǒng)一的覺得方案,定義一個(gè)函數(shù)來判斷和處理這一系列的情況,官方給出了一個(gè)叫做resolvePromise的函數(shù)

再看then方法

Promise.prototype.then = function (onFulfilled, onRjected) {
    //成功和失敗默認(rèn)不傳給一個(gè)函數(shù),解決了問題8
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : function (value) {
        return value;
    }
    onRjected = typeof onRjected === "function" ? onRjected : function (err) {
        throw err;
    }
    let _this = this;
    let promise2; //返回的promise
    if (_this.status === "resolved") {
        promise2 = new Promise(function (resolve, reject) {
            // 當(dāng)成功或者失敗執(zhí)行時(shí)有異常那么返回的promise應(yīng)該處于失敗狀態(tài)
            setTimeout(function () {// 根據(jù)規(guī)范讓那倆家伙異步執(zhí)行
                try {
                    let x = onFulfilled(_this.value);//這里解釋過了
                    // 寫一個(gè)方法統(tǒng)一處理問題1-7
                    resolvePromise(promise2, x, resolve, reject);
                } catch (e) {
                    reject(e);
                }
            })
        })
    }
    if (_this.status === "rejected") {
        promise2 = new Promise(function (resolve, reject) {
            setTimeout(function () {
                try {
                    let x = onRjected(_this.reason);
                    resolvePromise(promise2, x, resolve, reject);
                } catch (e) {
                    reject(e);
                }
            })
        })
    }
    if (_this.status === "pending") {
        promise2 = new Promise(function (resolve, reject) {
            _this.onResolvedCallbacks.push(function () {
                setTimeout(function () {
                    try {
                        let x = onFulfilled(_this.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e)
                    }
                })
            });
            _this.onRejectedCallbacks.push(function () {
                setTimeout(function () {
                    try {
                        let x = onRjected(_this.reason);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                })
            });
        })
    }
    return promise2;
}

接下來看看resolvePromise該怎么寫

function resolvePromise(promise2, x, resolve, reject) {
    // 接受四個(gè)參數(shù),新Promise、返回值,成功和失敗的回調(diào)
    // 有可能這里返回的x是別人的promise
    // 盡可能允許其他亂寫
    if (promise2 === x) { //這里應(yīng)該報(bào)一個(gè)類型錯(cuò)誤,來解決問題4
        return reject(new TypeError("循環(huán)引用了"))
    }
    // 看x是不是一個(gè)promise,promise應(yīng)該是一個(gè)對象
    let called; // 表示是否調(diào)用過成功或者失敗,用來解決問題7
    //下面判斷上一次then返回的是普通值還是函數(shù),來解決問題1、2
    if (x !== null && (typeof x === "object" || typeof x === "function")) {
        // 可能是promise {},看這個(gè)對象中是否有then方法,如果有then我就認(rèn)為他是promise了
        try {
            let then = x.then;// 保存一下x的then方法
            if (typeof then === "function") {
                // 成功
                //這里的y也是官方規(guī)范,如果還是promise,可以當(dāng)下一次的x使用
                //用call方法修改指針為x,否則this指向window
                then.call(x, function (y) {
                    if (called) return //如果調(diào)用過就return掉
                    called = true
                    // y可能還是一個(gè)promise,在去解析直到返回的是一個(gè)普通值
                    resolvePromise(promise2, y, resolve, reject)//遞歸調(diào)用,解決了問題6
                }, function (err) { //失敗
                    if (called) return
                    called = true
                    reject(err);
                })
            } else {
                resolve(x)
            }
        } catch (e) {
            if (called) return
            called = true;
            reject(e);
        }
    } else { // 說明是一個(gè)普通值1
        resolve(x); // 表示成功了
    }
}

測試一下

PromiseA+提供了測試庫promises-aplus-tests,github上明確講解了使用方法

公開一個(gè)適配器接口:

Promise.deferred = function () {
  let dfd = {};
  dfd.promise = new Promise(function (resolve, reject) {
      dfd.resolve = resolve;
      dfd.reject = reject;
  });
  return dfd
}

用命令行: promises-aplus-tests myPromise.js

經(jīng)過一系列測試得到結(jié)果

872 passing (18s)

證明了我們的promise是完全符合規(guī)范的!

其他方法

除了最重要的then方法,Promise還有很多方法,但都不難,這里一次性介紹一遍

    // 捕獲錯(cuò)誤的方法,在原型上有catch方法,返回一個(gè)沒有resolve的then結(jié)果即可
    Promise.prototype.catch = function (callback) {
        return this.then(null, callback)
    }
    // 解析全部方法,接收一個(gè)Promise數(shù)組promises,返回新的Promise,遍歷數(shù)組,都完成再resolve
    Promise.all = function (promises) {
        //promises是一個(gè)promise的數(shù)組
        return new Promise(function (resolve, reject) {
            let arr = []; //arr是最終返回值的結(jié)果
            let i = 0; // 表示成功了多少次
            function processData(index, y) {
                arr[index] = y;
                if (++i === promises.length) {
                    resolve(arr);
                }
            }
            for (let i = 0; i < promises.length; i++) {
                promises[i].then(function (y) {
                    processData(i, y)
                }, reject)
            }
        })
    }
    // 只要有一個(gè)promise成功了 就算成功。如果第一個(gè)失敗了就失敗了
    Promise.race = function (promises) {
        return new Promise(function (resolve, reject) {
            for (var i = 0; i < promises.length; i++) {
                promises[i].then(resolve,reject)
            }
        })
    }
    // 生成一個(gè)成功的promise
    Promise.resolve = function(value){
        return new Promise(function(resolve,reject){
            resolve(value);
        })
    }
    // 生成一個(gè)失敗的promise
    Promise.reject = function(reason){
        return new Promise(function(resolve,reject){
            reject(reason);
        })
    }

結(jié)語:Promise是異步的較好的解決方案之一,通過對源碼的解析,對Promise甚至js異步都有了深刻的理解。Promise已經(jīng)誕生很久了,如果你還不了解它,那你已經(jīng)很落后了,抓緊時(shí)間上車。程序世界一日千里,作為程序員,要主動(dòng)擁抱變化。

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/93734.html

相關(guān)文章

  • 細(xì)解JavaScript ES7 ES8 ES9 新特性

    摘要:定期召開會(huì)議,會(huì)議由會(huì)員公司的代表與特邀專家出席。新版本將會(huì)包含每年截止時(shí)間之前完成的所有特性。它引入了一個(gè)新的構(gòu)造函數(shù)和具有輔助函數(shù)的命名空間對象。 導(dǎo)言:ECMAScript的演化不會(huì)停止,但是我們完全沒必要害怕。除了ES6這個(gè)史無前例的版本帶來了海量的信息和知識點(diǎn)以外,之后每年一發(fā)的版本都僅僅帶有少量的增量更新,一年更新的東西花半個(gè)小時(shí)就能搞懂了,完全沒必要畏懼。本文將帶您花大約...

    Youngs 評論0 收藏0
  • ES6Promise:要優(yōu)雅,也要浪漫

    摘要:就算改變已經(jīng)發(fā)生了,即使再對對象添加回調(diào)函數(shù),也會(huì)立即得到這個(gè)結(jié)果。方法接收個(gè)參數(shù),第一個(gè)參數(shù)是狀態(tài)的回調(diào)函數(shù),第二個(gè)參數(shù)可選是狀態(tài)的回調(diào)函數(shù)。簡單來講,就是能把原來的回調(diào)寫法分離出來,在異步操作執(zhí)行完后,用鏈?zhǔn)秸{(diào)用的方式執(zhí)行回調(diào)函數(shù)。 在ECMAScript 6標(biāo)準(zhǔn)中,Promise被正式列為規(guī)范,Promise,字面意思就是許諾,承諾,嘿,聽著是不是很浪漫的說?我們來探究一下這個(gè)浪...

    weizx 評論0 收藏0
  • !ta竟然用Node.js對這些beauty圖做了這些事。。。

    摘要:做了什么一個(gè)用于爬取上妹子圖片的爬蟲。于是觀察瀏覽器正常瀏覽行為。在請求頭中設(shè)置和。解決該問題斷線繼續(xù)下載圖片下載個(gè)文件時(shí),經(jīng)常斷線。應(yīng)該是網(wǎng)站的飯爬蟲機(jī)制起了作用,暫時(shí)無法解決。于是在保存圖片時(shí)會(huì)先判斷圖片是否存在。 做了什么 一個(gè)用于爬取www.nvshens.com上妹子圖片的爬蟲。如有侵權(quán),馬上關(guān)閉showImg(https://segmentfault.com/img/bVR...

    mayaohua 評論0 收藏0
  • 使用Pandas&NumPy進(jìn)行數(shù)據(jù)清洗6大常用方法

    摘要:在這個(gè)教程中,我們將利用的和包來進(jìn)行數(shù)據(jù)清洗。在很多情況下,使用唯一的值作為索引值識別數(shù)據(jù)字段是非常有幫助的。清洗數(shù)據(jù)字段到現(xiàn)在為止,我們移除了不必要的列并改變了我們的索引變得更有意義。 作者:xiaoyu微信公眾號:Python數(shù)據(jù)科學(xué)知乎:Python數(shù)據(jù)分析師 數(shù)據(jù)科學(xué)家花了大量的時(shí)間清洗數(shù)據(jù)集,并將這些數(shù)據(jù)轉(zhuǎn)換為他們可以處理的格式。事實(shí)上,很多數(shù)據(jù)科學(xué)家聲稱開始獲取和清洗數(shù)據(jù)...

    siberiawolf 評論0 收藏0

發(fā)表評論

0條評論

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