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

資訊專欄INFORMATION COLUMN

寫一個(gè)符合promiseA+規(guī)范的promise實(shí)現(xiàn)

hatlonely / 2742人閱讀

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

如何寫一個(gè)符合promiseA+規(guī)范的promise實(shí)現(xiàn) 前言
Promise 是異步編程的一種解決方案:
從語(yǔ)法上講,promise是一個(gè)對(duì)象,從它可以獲取異步操作的消息;從本意上講,它是承諾,承諾它過(guò)一段時(shí)間會(huì)給你一個(gè)結(jié)果。
promise有三種狀態(tài):pending(等待態(tài)),fulfiled(成功態(tài)),rejected(失敗態(tài));狀態(tài)一旦改變,就不會(huì)再變。創(chuàng)造promise實(shí)例后,它會(huì)立即執(zhí)行。
編寫符合promiseA+規(guī)范的promise實(shí)現(xiàn)

在實(shí)現(xiàn)之前,可以先看一下Promise A plus規(guī)范

1. 創(chuàng)建promise構(gòu)造函數(shù)

這里先實(shí)現(xiàn)promise最基本的功能:promise創(chuàng)建后立即執(zhí)行;在then時(shí)執(zhí)行相應(yīng)的函數(shù);捕獲錯(cuò)誤立即變成reject態(tài)。

// promise里只有一個(gè)參數(shù),叫executor(執(zhí)行器)
function Promise(executor) {
    let self = this;
    self.status = "pending";//等待態(tài)
    self.value = undefined;//默認(rèn)成功的值
    self.err = undefined;//默認(rèn)失敗的值
    function resolve(value) {
        if (self.status === "pending") {
            self.status = "resolved";
            self.value = value;
        }
    }
    function reject(err) {
        if (self.status === "pending") {
            self.status = "rejected";
            self.err = err;
        }
    }
    try {//捕獲時(shí)發(fā)生異常,直接變成reject態(tài),拋出錯(cuò)誤
        executor(resolve, reject);//promise實(shí)例創(chuàng)建后,立即執(zhí)行
    } catch (error) {
        reject(error);  
    }
}
//在prototype上定義then實(shí)例方法
Promise.prototype.then = function (onFulfilled, onRejected) {
    let self = this;
    if (self.status === "resolved") {
        onFulfilled(self.value);
    }
    if (self.status === "rejected") {
        onRejected(self.err);
    }
}

這里我們先測(cè)試一下我們的Promise

這里便實(shí)現(xiàn)了基本功能,前面說(shuō)過(guò)Promise 是異步編程的一種解決方案;
我們加個(gè)異步邏輯運(yùn)行一下:

2. Promise異步調(diào)用
我們都知道異步代碼并不會(huì)立即執(zhí)行,這時(shí)既不是resolved也不是rejected,而是pending。
在之前的狀態(tài)判斷里面,正好丟了一個(gè)pending狀態(tài)。OK,這時(shí)需要在then里判斷當(dāng)status為pending時(shí),先將onFulfilled, onRejected存入數(shù)組里,當(dāng)status改變時(shí),再遍歷數(shù)組讓里面的函數(shù)依次執(zhí)行,看代碼。

(1)申明兩個(gè)存放onFulfiled,onRejected的數(shù)組

function Promise(resolver) {
    let self = this;
    self.status = "pending";//等待態(tài)
    self.value = undefined;//默認(rèn)成功的值
    self.err = undefined;//默認(rèn)失敗的值
    self.onResolvedCallbacks = []; // 存放then成功的回調(diào)
    self.onRejectedCallbacks = []; // 存放then失敗的回調(diào)
    function resolve(value) {
        if (self.status === "pending") {
            self.status = "resolved";
            self.value = value;
            self.onResolvedCallbacks.forEach(fn=>{//調(diào)用resolve時(shí),依次執(zhí)行數(shù)組里的函數(shù)
                fn();
            })
        }
    }
    function reject(err) {
        if (self.status === "pending") {
            self.status = "rejected";
            self.err = err;
            self.onRejectedCallbacks.forEach(fn=>{
                fn();
            })
        }
    }
    try {//捕獲時(shí)發(fā)生異常,直接拋出錯(cuò)誤
        resolver(resolve, reject);//promise實(shí)例創(chuàng)建后,立即執(zhí)行它的方法
    } catch (error) {
        reject(error)
    }
}

(2)接著在then方法里添加pending的判斷

Promise.prototype.then = function (onFulfilled, onRejected) {
    let self = this;
    if (self.status === "resolved") {
        onFulfilled(self.value);
    }
    if (self.status === "rejected") {
        onRejected(self.err);
    }
    if(self.status==="pending"){// 此時(shí)沒(méi)resolved,也沒(méi)rejectd
        self.onResolvedCallbacks.push(()=>{
            onFulfilled(self.value);
        });
        self.onRejectedCallbacks.push(()=>{
            onRejected(self.err);
        })
    }
}

再看剛剛的異步邏輯

1s后就執(zhí)行成功了,是不是很神奇,再看下面:

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

(1)規(guī)范里說(shuō)在同一個(gè)promise里then可以被多次調(diào)用。

(2)jquery能實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用靠的是返回this,而promise不能返回this,規(guī)范里又說(shuō)它返回的是一個(gè)新的Promise實(shí)例(注意,不是原來(lái)那個(gè)Promise實(shí)例);

在then里新建一個(gè)promise2并為每一個(gè)狀態(tài)包一個(gè)Promise

寫到這里,再來(lái)看看規(guī)范,規(guī)范里說(shuō)道
(1)x可能是一個(gè)promise;

(2)可能是一個(gè)對(duì)象或者方法;

(3)也有可能是一個(gè)普通的值。

這時(shí)需要一個(gè)方法來(lái)處理x

3.1 對(duì)onFulfilled和onRejected的返回值進(jìn)行處理

于是引入一個(gè)處理方法resolvePromise(promise2, x, resolve, reject);
這里需要注意一下,有些人寫的promise可能會(huì)既調(diào)用成功,又調(diào)用失敗,如果兩個(gè)都調(diào)用先調(diào)用誰(shuí)另一個(gè)就忽略掉。
于是增加一個(gè)判斷called表示是否調(diào)用過(guò)成功或者失敗,看代碼:

function resolvePromise(promise2, x, resolve, reject) {
    if (promise2 === x) {//promise2和x不能相同
        return reject(new TypeError("循環(huán)引用了"))
    }
    let called;// 表示是否調(diào)用過(guò)成功或者失敗
    //這里對(duì)x的類型進(jìn)行判斷
    if (x !== null && (typeof x === "object" || typeof x === "function")) {
        try {  // 判斷x是不是promise,如果x是對(duì)象并且x的then方法是函數(shù)我們就認(rèn)為他是一個(gè)promise
            let then = x.then;
            if (typeof then === "function") {
                then.call(x, function (y) {
                    if (called) return
                    called = true
                    // y可能還是一個(gè)promise,在去解析直到返回的是一個(gè)普通值
                    resolvePromise(promise2, y, resolve, reject)
                }, function (err) { //失敗
                    if (called) return
                    called = true
                    reject(err);
                })
            } else {
                resolve(x)
            }
        } catch (e) {
            if (called) return
            called = true;
            reject(e);
        }
    } else { // 說(shuō)明是一個(gè)普通值1
        resolve(x); // 表示成功了
    }
}

相應(yīng)的將前面的代碼進(jìn)行一些更改

4. 值的穿透問(wèn)題

如果在then中什么都不傳,值會(huì)穿透到最后調(diào)用的時(shí)候;

這時(shí)需要在then里給onFulfilled和onRejected寫一個(gè)默認(rèn)的函數(shù)

 onFulfilled = typeof onFulfilled === "function" ? onFulfilled : function (value) {
        return value;
    }
    onRejected = typeof onRejected === "function" ? onRejected : function (err) {
        throw err;//這里需要拋出錯(cuò)誤,不能return err,否則會(huì)在下一次調(diào)用成功態(tài)
    }
5. then的異步實(shí)現(xiàn)

規(guī)范里要求,所有的onFulfilled和onRejected都要確保異步執(zhí)行

這里以resolve為例,寫一個(gè)setTimeout():

6. defer語(yǔ)法糖

在使用promise的過(guò)程中,我們都需要先new Promise(),比如說(shuō):

function read() {
    let fs = require("fs");
    let promise = new Promise(function(resolve,reject){
        fs.readFile("./1.txt","utf8",function(err,data){
            if(err) reject(err);
            resolve(data);
        })
    });
    return promise
}

在Promise中,它為我們提供了一個(gè)語(yǔ)法糖Promise.defer,用Promise.defer只需這樣寫:

function read() {
    let defer = Promise.defer()
    require("fs").readFile(".//1.txt", "utf8", function (err, data) {
        if(err) defer.reject(err);
        defer.resolve(data);
    })
    return defer.promise;
}

為此,再為我們的Promise加一個(gè)defer方法:

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

在這里,我們基本實(shí)現(xiàn)了一個(gè)比較完整的promise;當(dāng)然Promise還有許多靜態(tài)方法,還有js的異步發(fā)展史,這些可以在下一次進(jìn)行討論。
完整代碼:

// promise里只有一個(gè)參數(shù),叫executor(執(zhí)行器)
function Promise(executor) {
    let self = this;
    self.status = "pending";//等待態(tài)
    self.value = undefined;//默認(rèn)成功的值
    self.err = undefined;//默認(rèn)失敗的值
    self.onResolvedCallbacks = []; // 存放then成功的回調(diào)
    self.onRejectedCallbacks = []; // 存放then失敗的回調(diào)
    function resolve(value) {
        if (self.status === "pending") {
            self.status = "resolved";
            self.value = value;
            self.onResolvedCallbacks.forEach(function (fn) {
                fn();
            });
        }
    }
    function reject(err) {
        if (self.status === "pending") {
            self.status = "rejected";
            self.err = err;
            self.onRejectedCallbacks.forEach(function (fn) {
                fn();
            });
        }
    }
    try {//捕獲時(shí)發(fā)生異常,直接變成reject態(tài),拋出錯(cuò)誤
        executor(resolve, reject);//promise實(shí)例創(chuàng)建后,立即執(zhí)行
    } catch (error) {
        reject(error);  
    }
}
function resolvePromise(promise2, x, resolve, reject) {
    if (promise2 === x) {//promise2和x不能相同
        return reject(new TypeError("循環(huán)引用了"))
    }
    let called;// 表示是否調(diào)用過(guò)成功或者失敗
    //這里對(duì)x的類型進(jìn)行判斷
    if (x !== null && (typeof x === "object" || typeof x === "function")) {
        try {  // 判斷x是不是promise,如果x是對(duì)象并且x的then方法是函數(shù)我們就認(rèn)為他是一個(gè)promise
            let then = x.then;
            if (typeof then === "function") {
                then.call(x, function (y) {
                    if (called) return
                    called = true
                    // y可能還是一個(gè)promise,在去解析直到返回的是一個(gè)普通值
                    resolvePromise(promise2, y, resolve, reject)
                }, function (err) { //失敗
                    if (called) return
                    called = true
                    reject(err);
                })
            } else {
                resolve(x)
            }
        } catch (e) {
            if (called) return
            called = true;
            reject(e);
        }
    } else { // 說(shuō)明是一個(gè)普通值1
        resolve(x); // 表示成功了
    }
}
//在prototype上定義then實(shí)例方法
Promise.prototype.then = function (onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : function (value) {
        return value;
    }
    onRejected = typeof onRejected === "function" ? onRejected : function (err) {
        throw err;//這里需要拋出錯(cuò)誤,不能return err,否則會(huì)在下一次調(diào)用成功態(tài)
    }
    let self = this;
    let promise2; //返回的promise
    if (self.status === "resolved") {
        promise2 = new Promise(function (resolve, reject) {
            setTimeout(function () {
                try {
                    let x = onFulfilled(self.value);
                    resolvePromise(promise2, x, resolve, reject);
                } catch (e) {
                    reject(e);
                }
            })
        })
    }
    if (self.status === "rejected") {
        promise2 = new Promise(function (resolve, reject) {
            setTimeout(function () {
                try {
                    let x = onRejected(self.err);
                    resolvePromise(promise2, x, resolve, reject);
                } catch (e) {
                    reject(e);
                }
            })

        })
    }
    // 當(dāng)調(diào)用then時(shí)可能沒(méi)成功 也沒(méi)失敗
    if (self.status === "pending") {
        promise2 = new Promise(function (resolve, reject) {
            // 此時(shí)沒(méi)有resolve 也沒(méi)有reject
            self.onResolvedCallbacks.push(function () {
                setTimeout(function () {
                    try {
                        let x = onFulfilled(self.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e)
                    }
                })
            });
            self.onRejectedCallbacks.push(function () {
                setTimeout(function () {
                    try {
                        let x = onRejected(self.err);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                })
            });
        })
    }
    return promise2;
}
Promise.defer = Promise.deferred = function () {
    let dfd = {};
    dfd.promise = new Promise(function (resolve, reject) {
        dfd.resolve = resolve;
        dfd.reject = reject;
    });
    return dfd
}

module.exports = Promise;
7.Promise測(cè)試
npm i -g promises-aplus-tests
promises-aplus-tests Promise.js

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

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

相關(guān)文章

  • Promise源碼實(shí)現(xiàn)(完美符合Promise/A+規(guī)范

    摘要:以上代碼,可以完美通過(guò)所有用例。在的函數(shù)中,為何需要這個(gè)同樣是因?yàn)橐?guī)范中明確表示因此我們需要這樣的來(lái)確保只會(huì)執(zhí)行一次。其他情況,直接返回以該值為成功狀態(tài)的對(duì)象。 Promise是前端面試中的高頻問(wèn)題,我作為面試官的時(shí)候,問(wèn)Promise的概率超過(guò)90%,據(jù)我所知,大多數(shù)公司,都會(huì)問(wèn)一些關(guān)于Promise的問(wèn)題。如果你能根據(jù)PromiseA+的規(guī)范,寫出符合規(guī)范的源碼,那么我想,對(duì)于面試...

    gaomysion 評(píng)論0 收藏0
  • 一步一步實(shí)現(xiàn)一個(gè)符合PromiseA+規(guī)范Promise庫(kù)(1)

    摘要:今天我們來(lái)自己手寫一個(gè)符合規(guī)范的庫(kù)。是異步編程的一種解決方案,比傳統(tǒng)的解決方案回調(diào)函數(shù)和事件更合理和更強(qiáng)大。我們可以看到,其實(shí)就是一個(gè)構(gòu)造函數(shù)。所以說(shuō)我們的數(shù)組里存的是一個(gè)一個(gè)的的回調(diào)函數(shù),也就是一個(gè)一個(gè)。 今天我們來(lái)自己手寫一個(gè)符合PromiseA+規(guī)范的Promise庫(kù)。大家是不是很激動(dòng)呢?? showImg(https://segmentfault.com/img/bV6t4Z?...

    joyvw 評(píng)論0 收藏0
  • 一步一步實(shí)現(xiàn)一個(gè)符合PromiseA+規(guī)范Promise庫(kù)(2)

    摘要:我們都知道,方法中有和兩個(gè)回調(diào)函數(shù),所以我們要處理一下這兩個(gè)回調(diào)函數(shù)。我們實(shí)現(xiàn)了異步調(diào)用,在方法中返回或者值,實(shí)現(xiàn)了方法中可以沒(méi)有回調(diào)函數(shù)也能把執(zhí)行結(jié)果傳入下一次的方法中。 Hello everybody。我又來(lái)啦,還記得我們上一張實(shí)現(xiàn)的內(nèi)容嗎? showImg(https://segmentfault.com/img/bV6UaU?w=102&h=95); 上一張我們實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的...

    jsliang 評(píng)論0 收藏0
  • 實(shí)現(xiàn)一個(gè)符合標(biāo)準(zhǔn)Promise

    摘要:不同的的實(shí)現(xiàn)需要可以相互調(diào)用,搞清楚了標(biāo)準(zhǔn)之后,開始動(dòng)手吧構(gòu)造函數(shù)產(chǎn)生一個(gè)對(duì)象有很多種方法,構(gòu)造函數(shù)是看起來(lái)最面向?qū)ο蟮囊环N,而且原生實(shí)現(xiàn)也是使用的構(gòu)造函數(shù),因此我也決定使用構(gòu)造函數(shù)的方法。 -- What i cant create, i dont understant 前言 實(shí)現(xiàn)Promise的目的是為了深入的理解Promies,以在項(xiàng)目中游刃有余的使用它。完整的代碼見gitHub...

    yuanzhanghu 評(píng)論0 收藏0
  • 啥?喝著闊落吃著西瓜就把Promise出來(lái)了???

    摘要:嗝首先,我們通過(guò)字面可以看出來(lái)是一種解決方案,而且還有兩種傳統(tǒng)的解決方案回調(diào)函數(shù)和事件,,那么我們就來(lái)先聊聊這兩種方案。 前言 雖然今年已經(jīng)18年,但是今天還是要繼續(xù)聊聊ES6的東西,ES6已經(jīng)過(guò)去幾年,可是我們對(duì)于ES6的語(yǔ)法究竟是掌握了什么程度,是了解?會(huì)用?還是精通?相信大家和我一樣都對(duì)自己有著一個(gè)提升的心,對(duì)于新玩具可不能僅僅了解,對(duì)于其中的思想才是最吸引人的,所以接下來(lái)會(huì)通過(guò)...

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

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

0條評(píng)論

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