91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaScript怎么實現手寫promise

發布時間:2023-05-06 09:43:22 來源:億速云 閱讀:145 作者:zzz 欄目:開發技術

這篇文章主要介紹了JavaScript怎么實現手寫promise的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇JavaScript怎么實現手寫promise文章都會有所收獲,下面我們一起來看看吧。

需求

我們先來總結一下 promise 的特性:

使用:

const p1 = new Promise((resolve, reject) => {
  console.log('1');
  resolve('成功了');
})

console.log("2");

const p2 = p1.then(data => {
  console.log('3')
  throw new Error('失敗了')
})

const p3 = p2.then(data => {
  console.log('success', data)
}, err => {
  console.log('4', err)
})

JavaScript怎么實現手寫promise

JavaScript怎么實現手寫promise

以上的示例可以看出 promise 的一些特點,也就是我們本次要做的事情:

  • 在調用 Promise 時,會返回一個 Promise 對象,包含了一些熟悉和方法(all/resolve/reject/then…)

  • 構建 Promise 對象時,需要傳入一個 executor 函數,接受兩個參數,分別是resolve和reject,Promise 的主要業務流程都在 executor 函數中執行。

  • 如果運行在 excutor 函數中的業務執行成功了,會調用 resolve 函數;如果執行失敗了,則調用 reject 函數。

  • promise 有三個狀態:pending,fulfilled,rejected,默認是 pending。只能從pending到rejected, 或者從pending到fulfilled,狀態一旦確認,就不會再改變;

  • promise 有一個then方法,接收兩個參數,分別是成功的回調 onFulfilled, 和失敗的回調 onRejected。

// 三個狀態:PENDING、FULFILLED、REJECTED
const PENDING = "PENDING";
const FULFILLED = "FULFILLED";
const REJECTED = "REJECTED";

class Promise {
  constructor(executor) {
    // 默認狀態為 PENDING
    this.status = PENDING;
    // 存放成功狀態的值,默認為 undefined
    this.value = undefined;
    // 存放失敗狀態的值,默認為 undefined
    this.reason = undefined;

    // 調用此方法就是成功
    let resolve = (value) => {
      // 狀態為 PENDING 時才可以更新狀態,防止 executor 中調用了兩次 resovle/reject 方法
      if (this.status === PENDING) {
        this.status = FULFILLED;
        this.value = value;
      }
    };

    // 調用此方法就是失敗
    let reject = (reason) => {
      // 狀態為 PENDING 時才可以更新狀態,防止 executor 中調用了兩次 resovle/reject 方法
      if (this.status === PENDING) {
        this.status = REJECTED;
        this.reason = reason;
      }
    };

    try {
      // 立即執行,將 resolve 和 reject 函數傳給使用者
      executor(resolve, reject);
    } catch (error) {
      // 發生異常時執行失敗邏輯
      reject(error);
    }
  }

  // 包含一個 then 方法,并接收兩個參數 onFulfilled、onRejected
  then(onFulfilled, onRejected) {
    if (this.status === FULFILLED) {
      onFulfilled(this.value);
    }

    if (this.status === REJECTED) {
      onRejected(this.reason);
    }
  }
}

調用一下:

const promise = new Promise((resolve, reject) => {
  resolve('成功');
}).then(
  (data) => {
    console.log('success', data)
  },
  (err) => {
    console.log('faild', err)
  }
)

JavaScript怎么實現手寫promise

這個時候我們很開心,但是別開心的太早,promise 是為了處理異步任務的,我們來試試異步任務好不好使:

const promise = new Promise((resolve, reject) => {
  // 傳入一個異步操作
  setTimeout(() => {
    resolve('成功');
  },1000);
}).then(
  (data) => {
    console.log('success', data)
  },
  (err) => {
    console.log('faild', err)
  }
)

發現沒有任何輸出,我們來分析一下為什么:

new Promise 執行的時候,這時候異步任務開始了,接下來直接執行 .then 函數,then函數里的狀態目前還是 padding,所以就什么也沒執行。

那么我們想想應該怎么改呢?

我們想要做的就是,當異步函數執行完后,也就是觸發 resolve 的時候,再去觸發 .then 函數執行并把 resolve 的參數傳給 then。

這就是典型的發布訂閱的模式,可以看我這篇文章。

const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';

class Promise {
  constructor(executor) {
    this.status = PENDING;
    this.value = undefined;
    this.reason = undefined;
    // 存放成功的回調
    this.onResolvedCallbacks = [];
    // 存放失敗的回調
    this.onRejectedCallbacks= [];

    let resolve = (value) => {
      if(this.status ===  PENDING) {
        this.status = FULFILLED;
        this.value = value;
        // 依次將對應的函數執行
        this.onResolvedCallbacks.forEach(fn=>fn());
      }
    } 

    let reject = (reason) => {
      if(this.status ===  PENDING) {
        this.status = REJECTED;
        this.reason = reason;
        // 依次將對應的函數執行
        this.onRejectedCallbacks.forEach(fn=>fn());
      }
    }

    try {
      executor(resolve,reject)
    } catch (error) {
      reject(error)
    }
  }

  then(onFulfilled, onRejected) {
    if (this.status === FULFILLED) {
      onFulfilled(this.value)
    }

    if (this.status === REJECTED) {
      onRejected(this.reason)
    }

    if (this.status === PENDING) {
      // 如果promise的狀態是 pending,需要將 onFulfilled 和 onRejected 函數存放起來,等待狀態確定后,再依次將對應的函數執行
      this.onResolvedCallbacks.push(() => {
        onFulfilled(this.value)
      });

      // 如果promise的狀態是 pending,需要將 onFulfilled 和 onRejected 函數存放起來,等待狀態確定后,再依次將對應的函數執行
      this.onRejectedCallbacks.push(()=> {
        onRejected(this.reason);
      })
    }
  }
}

這下再進行測試:

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('成功');
  },1000);
}).then(
  (data) => {
    console.log('success', data)
  },
  (err) => {
    console.log('faild', err)
  }
)

1s 后輸出了:

JavaScript怎么實現手寫promise

說明成功啦

then的鏈式調用

這里就不分析細節了,大體思路就是每次 .then 的時候重新創建一個 promise 對象并返回 promise,這樣下一個 then 就能拿到前一個 then 返回的 promise 了。

const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';

const resolvePromise = (promise2, x, resolve, reject) => {
  // 自己等待自己完成是錯誤的實現,用一個類型錯誤,結束掉 promise  Promise/A+ 2.3.1
  if (promise2 === x) { 
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
  }
  // Promise/A+ 2.3.3.3.3 只能調用一次
  let called;
  // 后續的條件要嚴格判斷 保證代碼能和別的庫一起使用
  if ((typeof x === 'object' && x != null) || typeof x === 'function') { 
    try {
      // 為了判斷 resolve 過的就不用再 reject 了(比如 reject 和 resolve 同時調用的時候)  Promise/A+ 2.3.3.1
      let then = x.then;
      if (typeof then === 'function') { 
        // 不要寫成 x.then,直接 then.call 就可以了 因為 x.then 會再次取值,Object.defineProperty  Promise/A+ 2.3.3.3
        then.call(x, y => { // 根據 promise 的狀態決定是成功還是失敗
          if (called) return;
          called = true;
          // 遞歸解析的過程(因為可能 promise 中還有 promise) Promise/A+ 2.3.3.3.1
          resolvePromise(promise2, y, resolve, reject); 
        }, r => {
          // 只要失敗就失敗 Promise/A+ 2.3.3.3.2
          if (called) return;
          called = true;
          reject(r);
        });
      } else {
        // 如果 x.then 是個普通值就直接返回 resolve 作為結果  Promise/A+ 2.3.3.4
        resolve(x);
      }
    } catch (e) {
      // Promise/A+ 2.3.3.2
      if (called) return;
      called = true;
      reject(e)
    }
  } else {
    // 如果 x 是個普通值就直接返回 resolve 作為結果  Promise/A+ 2.3.4  
    resolve(x)
  }
}

class Promise {
  constructor(executor) {
    this.status = PENDING;
    this.value = undefined;
    this.reason = undefined;
    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks= [];

    let resolve = (value) => {
      if(this.status ===  PENDING) {
        this.status = FULFILLED;
        this.value = value;
        this.onResolvedCallbacks.forEach(fn=>fn());
      }
    } 

    let reject = (reason) => {
      if(this.status ===  PENDING) {
        this.status = REJECTED;
        this.reason = reason;
        this.onRejectedCallbacks.forEach(fn=>fn());
      }
    }

    try {
      executor(resolve,reject)
    } catch (error) {
      reject(error)
    }
  }

  then(onFulfilled, onRejected) {
    //解決 onFufilled,onRejected 沒有傳值的問題
    //Promise/A+ 2.2.1 / Promise/A+ 2.2.5 / Promise/A+ 2.2.7.3 / Promise/A+ 2.2.7.4
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
    //因為錯誤的值要讓后面訪問到,所以這里也要跑出個錯誤,不然會在之后 then 的 resolve 中捕獲
    onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
    // 每次調用 then 都返回一個新的 promise  Promise/A+ 2.2.7
    let promise2 = new Promise((resolve, reject) => {
      if (this.status === FULFILLED) {
        //Promise/A+ 2.2.2
        //Promise/A+ 2.2.4 --- setTimeout
        setTimeout(() => {
          try {
            //Promise/A+ 2.2.7.1
            let x = onFulfilled(this.value);
            // x可能是一個proimise
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            //Promise/A+ 2.2.7.2
            reject(e)
          }
        }, 0);
      }

      if (this.status === REJECTED) {
        //Promise/A+ 2.2.3
        setTimeout(() => {
          try {
            let x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e)
          }
        }, 0);
      }

      if (this.status === PENDING) {
        this.onResolvedCallbacks.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.all

核心就是有一個失敗則失敗,全成功才進行 resolve

Promise.all = function(values) {
  if (!Array.isArray(values)) {
    const type = typeof values;
    return new TypeError(`TypeError: ${type} ${values} is not iterable`)
  }
  return new Promise((resolve, reject) => {
    let resultArr = [];
    let orderIndex = 0;
    const processResultByKey = (value, index) => {
      resultArr[index] = value;
      if (++orderIndex === values.length) {
          resolve(resultArr)
      }
    }
    for (let i = 0; i < values.length; i++) {
      let value = values[i];
      if (value && typeof value.then === 'function') {
        value.then((value) => {
          processResultByKey(value, i);
        }, reject);
      } else {
        processResultByKey(value, i);
      }
    }
  });
}

關于“JavaScript怎么實現手寫promise”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“JavaScript怎么實現手寫promise”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

福建省| 枝江市| 东源县| 永顺县| 洛宁县| 四平市| 达尔| 沾化县| 额济纳旗| 宜宾市| 漠河县| 北碚区| 南开区| 巢湖市| 永胜县| 赣州市| 汉阴县| 伊金霍洛旗| 宁陵县| 梁河县| 崇左市| 阳西县| 云龙县| 西平县| 建湖县| 黑河市| 宝清县| 邮箱| 忻城县| 凤阳县| 元氏县| 贵定县| 禹城市| 文安县| 班玛县| 台江县| 高淳县| 都江堰市| 嘉禾县| 玉树县| 巢湖市|