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

資訊專欄INFORMATION COLUMN

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

hatlonely / 2787人閱讀

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

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

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

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

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

// promise里只有一個參數(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 {//捕獲時發(fā)生異常,直接變成reject態(tài),拋出錯誤
        executor(resolve, reject);//promise實例創(chuàng)建后,立即執(zhí)行
    } catch (error) {
        reject(error);  
    }
}
//在prototype上定義then實例方法
Promise.prototype.then = function (onFulfilled, onRejected) {
    let self = this;
    if (self.status === "resolved") {
        onFulfilled(self.value);
    }
    if (self.status === "rejected") {
        onRejected(self.err);
    }
}

這里我們先測試一下我們的Promise

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

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

(1)申明兩個存放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時,依次執(zhí)行數(shù)組里的函數(shù)
                fn();
            })
        }
    }
    function reject(err) {
        if (self.status === "pending") {
            self.status = "rejected";
            self.err = err;
            self.onRejectedCallbacks.forEach(fn=>{
                fn();
            })
        }
    }
    try {//捕獲時發(fā)生異常,直接拋出錯誤
        resolver(resolve, reject);//promise實例創(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"){// 此時沒resolved,也沒rejectd
        self.onResolvedCallbacks.push(()=>{
            onFulfilled(self.value);
        });
        self.onRejectedCallbacks.push(()=>{
            onRejected(self.err);
        })
    }
}

再看剛剛的異步邏輯

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

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

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


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


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

寫到這里,再來看看規(guī)范,規(guī)范里說道
(1)x可能是一個promise;


(2)可能是一個對象或者方法;


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


這時需要一個方法來處理x

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

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

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

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

4. 值的穿透問題

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

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

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

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


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

6. defer語法糖

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

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中,它為我們提供了一個語法糖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加一個defer方法:

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

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

// promise里只有一個參數(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 {//捕獲時發(fā)生異常,直接變成reject態(tài),拋出錯誤
        executor(resolve, reject);//promise實例創(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)用過成功或者失敗
    //這里對x的類型進(jìn)行判斷
    if (x !== null && (typeof x === "object" || typeof x === "function")) {
        try {  // 判斷x是不是promise,如果x是對象并且x的then方法是函數(shù)我們就認(rèn)為他是一個promise
            let then = x.then;
            if (typeof then === "function") {
                then.call(x, function (y) {
                    if (called) return
                    called = true
                    // y可能還是一個promise,在去解析直到返回的是一個普通值
                    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 { // 說明是一個普通值1
        resolve(x); // 表示成功了
    }
}
//在prototype上定義then實例方法
Promise.prototype.then = function (onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : function (value) {
        return value;
    }
    onRejected = typeof onRejected === "function" ? onRejected : function (err) {
        throw err;//這里需要拋出錯誤,不能return err,否則會在下一次調(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時可能沒成功 也沒失敗
    if (self.status === "pending") {
        promise2 = new Promise(function (resolve, reject) {
            // 此時沒有resolve 也沒有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測試
npm i -g promises-aplus-tests
promises-aplus-tests Promise.js

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

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

相關(guān)文章

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

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

    gaomysion 評論0 收藏0
  • 一步一步實現(xiàn)一個符合PromiseA+規(guī)范Promise庫(1)

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

    joyvw 評論0 收藏0
  • 一步一步實現(xiàn)一個符合PromiseA+規(guī)范Promise庫(2)

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

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

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

    yuanzhanghu 評論0 收藏0
  • 啥?喝著闊落吃著西瓜就把Promise出來了???

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

    idisfkj 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<