Promise/a+規範

promise/a+規範概念

Promise/A+ 是 Promise 最小的一個規範,它包括:npm

1 promise狀態
2 then方法
3 promise解析過程

任何能跑通測試的 Promise 實現都被 Promise/A+ 承認。promise

promise/a+出現的緣由

1 咱們不知道異步請求何時返回數據,因此咱們就須要些回調函數。可是在某些狀況下咱們須要知道數據是在何時返回的,而後進行一些處理。
2 當咱們在異步回調裏面處理的操做仍是異步操做的時候,這樣就造成了異步回調的嵌套

那麼咱們就按照這個文檔來寫一個可經過測試的promise吧(https://www.ituring.com.cn/ar... 寫以前最好讀幾遍規範內容。話很少少,上代碼,爲了更好的展現我給代碼打了不少註釋,雖然很亂可是挺清楚的異步

//規範三種狀態,默認是pending;定義宏變量是爲了書寫時方便一點
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

function resolvePromise(promise2, x, resolve, reject) {
`若是promise和x指向同一對象,以TypeError爲據因拒絕執行promise`
    if (promise2 === x) {
        reject(new TypeError('Chaining cycle detected for promise #<Promise>--'))
    }
    let called;
    `判斷若是是對象或者函數`
    if ((typeof x === 'object' && x != null) || typeof  x === 'function') {  
        try {
        `文檔規定`
            let then = x.then;
            if (typeof then === 'function') {
            `若是then是函數,將x做爲函數的做用域this調用之,傳遞兩個回調函數做爲參數`
                then.call(x, y => {
                `防止重複調用`
                    if (called) return;
                    called = true;
                    `若是是嵌套的promise那麼須要遞歸遍歷到普通值爲止`
                    resolvePromise(promise2, y, resolve, reject)
                }, r => {
                 `防止重複調用`
                    if (called) return;
                    called = true;
                    reject(r)
                })
            } else {
          `若是then不是函數,以x爲參數執行promise`
                resolve(x)
            }
        } catch (e) {
         `防止重複調用`
            if (called) return;
            called = true;
            `若是取x.then的值時拋出錯誤e,則以e爲據因拒絕promise`
            reject(e)
        }
    } else {
    `若是是普通值`
        resolve(x)
    }
}
`建立一個promise類`
class Promise {
    constructor(executor) {
        this.status = PENDING;
        this.value = undefined;
        this.reason = undefined;
        this.onFulfilledCallbacks = [];
        this.onRejectedCallbacks = [];
        `定義executor(resolve, reject)中的resolve,參數value`
        let resolve = value => {
        `只有狀態爲pending的狀況下才能轉換狀態`
            if (this.status === PENDING) {
            `調用reslove函數 狀態變爲成功態`
                this.status = FULFILLED;
                `定義變量接受傳進來的參數`
                this.value = value;
                `遍歷成功事件池中的方法並依次執行(解決異步)`
                this.onFulfilledCallbacks.forEach(fn => fn())
            }
        };
      `定義executor(resolve, reject)中的reject,參數reason`
        let reject = reason => {
       `只有狀態爲pending的狀況下才能轉換狀態`
            if (this.status === PENDING) {
              `調用reject函數 狀態變爲失敗態`
                this.status = REJECTED;
                `定義變量接受傳進來的參數`
                this.reason = reason;
                `遍歷失敗事件池中的方法並依次執行(解決異步)`
                this.onRejectedCallbacks.forEach(fn => fn())
            }
        };
        try {
         `默認傳進一個函數executor,而且執行,promise中的提供兩個函數`
            executor(resolve, reject)
        } catch (e) {
        `若是拋錯調用reject(文檔寫的)`
            reject(e)
        }

    }

    then(onFulfilled, onRejected) {
    `(成功態)連續調用時若是函數沒有寫給他附一個默認值繼續向下傳遞`
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : d => d;
         `(失敗態)若是函數沒有寫,那就把錯誤拋出去`
        onRejected = typeof onRejected === 'function' ? onRejected : e => {
            throw e
        };
        `規範上寫調用.then時必須返回promise`
        let promise2 = new Promise((resolve, reject) => {
        `若是狀態爲成功態`
            if (this.status === FULFILLED) {
                setTimeout(() => {
                    try {
                    `接受.then後面第一個函數的返回值,爲了判斷有沒有拋錯使用了try包裹`
                        let x = onFulfilled(this.value);
                        `判斷x是promise仍是普通值,從而進行不一樣的處理,當調用這個函數時獲取不到promise因此這裏使用了異步`
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                    `若是拋錯以後調用reject方法以e做爲緣由`
                        reject(e)
                    }
                }, 0);
            }
            if (this.status === REJECTED) {
                setTimeout(() => {
                    try {
                        let x = onRejected(this.reason);
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0);
            }
            if (this.status === PENDING) {
          `若是是異步的話,使用發佈訂閱模式,將事件放到對應的事件池中`
                this.onFulfilledCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onFulfilled(this.value);
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                });
                this.onRejectedCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onRejected(this.reason);
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                })
            }
        });
        return promise2;//返回一個promise
    }
}

//導出咱們本身寫的promise
module.exports = Promise;

測試

1.安裝測試腳本函數

npm i -g promises-aplus-tests

2.在咱們寫的promise中寫入代碼測試

//測試代碼
Promise.defer = Promise.deferred = function () {
    let dfd = {};
    dfd.promise = new Promise((resolve, reject) => {
        dfd.resolve = resolve;
        dfd.reject = reject;
    })
    return dfd
}

3.在當前文件夾下執行this

promises-aplus-tests xxx.js(本身寫promise的文件)
相關文章
相關標籤/搜索