JS 手寫promise 實現


 function MyPromise (execute) {
     // value 記錄異步任務成功的執行結果
     this.value = null;
      // reason 記錄異步任務失敗的執行結果
     this.reason = null;
     // status 記錄當前狀態,初始化pending
     this.status = 'pending';

     this.onResolvedQueue = [];
     this.onRejectedQueue = [];

     let self = this;

     function resolve(value) {
         if(self.status !== 'pending' ) {
            return
         }
         // 異步任務成功,把結果賦值給value
         self.value = value;
         // 把當前狀態切換為resolved
         self.status = 'resolved';

         self.onResolvedQueue.forEach(resolved => resolved(self.value))
     }

     function reject(reason) {
        if(self.status !== 'pending' ) {
            return
         }
        // 異步任務失敗,把結果賦值給value
        self.reason = reason;
         // 把當前狀態切換為rejected
        self.status = 'rejected';

        self.onRejectedQueue.forEach(rejected => rejected(self.reason))
    }

    // 把resolve和reject能力 賦予執行器
    try {
        execute(resolve, reject);

    }catch(e) {
        reject(e)
    }

}

// then方法接受兩個函數作為入參(可選)
MyPromise.prototype.then = function (onResolved, onRejected) {
    // 注意, onResolved 和 onRejected  必須是函數; 如果不是,我們此處用一個透傳來兜底
    if(typeof onResolved !== 'function') {
        onResolved = function(x) {return x};
    }
    if(typeof onRejected !== 'function') {
        onRejected = function(e) {throw e};
    }
    let self = this;
    // 保存返回值x
    let x = null;

    // resolve 狀態處理函數
    function resolveByStatus(resolve, reject) {
        // 包裝成異步, 確保在then后執行
        setTimeout(() => {
            try {
                x = onResolved(self.value)
                resolutionProcedure(promise2, x, resolve, reject);
            } catch(e) {
                reject(e)
            }
        })
    }

    // reject 狀態處理函數
    function rejectByStatus(resolve, reject) {
        setTimeout(() => {
            try {
                x = onRejected(self.reason)
                resolutionProcedure(promise2, x, resolve, reject);
            } catch(e) {
                reject(e)
            }
        })
    }

    let promise2 = new MyPromise((resolve, reject) => {
        // 判斷是否是resolved狀態
        if(self.status === 'resolved') {
            // 如果是 執行對應的處理方法
            resolveByStatus(resolve, reject)
        } else if(self.status === 'rejected') {
            // 若是rejected 狀態, 則執行rejected 對應方法
            rejectByStatus(resolve, reject)
        } else if(self.status === 'pending') {
            self.onResolvedQueue.push(() => resolveByStatus(resolve, reject))
            self.onRejectedQueue.push(() => rejectByStatus(resolve, reject))
        }
    })
    return promise2;
}


function resolutionProcedure(promise2, x, resolve, reject) {
    // 不被重復執行
    let hasCalled = null;

    if(x === promise2) {
        return reject(new TypeError('循環引用'))
    } else if((typeof x === 'object'&& x !== null) || typeof x === 'function') {
        try {
            let then = x.then;
            if(typeof then === 'function') {
                then.call(x, (y) => {
                    if( hasCalled ) return
                    hasCalled = true;

                    resolutionProcedure(promise2, y, resolve, reject);
                }, (err) => {
                    if( hasCalled ) return
                    hasCalled = true;
                    reject(err)
                })
            } else {
                // 如果then不是function, 則x為參數執行promise
                resolve(x);
            }

        } catch(e) {
            if( hasCalled ) return
            hasCalled = true;
            reject(err)
        }

    } else {
        // 如果x不是object或者function, 則x為參數執行promise
        resolve(x);
    }

}

let promise2 = new MyPromise(function(resolve, reject) {
// let MyPromise = new Promise(function(resolve, reject) {
    resolve('成了');
  
})
promise2.then((value) => {
    console.log('value:', value, '第一個任務')
    return '我第一個個任務傳遞過來的'
}).then((value) => {
    console.log('第二個任務', value)
})

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM