promise、async/await的提出,已由來已久,不少人都知道這兩個都是爲了解決回調地獄問題的,面試中不少面試官都喜歡那這兩個做比較,那我今天就來講說promise、async/await的區別以及簡單的原理實現。避免面試的尷尬!
篇幅比較長,理解和實現兩部分(主要在實現),最近看到不少面試的同窗都有提到手寫promise、async/await的問題,就隨手整理了一下,以前也整理了一下嘮一嘮call、apply和bind以及手動實現(拒絕晦澀難懂))git
Promise,簡單來講就是一個容器,裏面保存着某個將來纔會結束的時間(一般是一個異步操做的結果),經過鏈式調用同步實現異步;github
特色:面試
具體的能夠關注下關於Promise以及你可能不知道的6件事以及聊一聊Promise的坑npm
這篇剖析Promise內部結構寫的很不錯,這裏也分享給你們,面試當中寫個很簡單的就能夠了,對於源碼咱們理解便可;編程
實現Promise的要求:segmentfault
基於以上要求咱們能夠實現一個簡單的Promise:promise
// promise 三個狀態 const PENDING = "pending"; const FULFILLED = "fulfilled"; const REJECTED = "rejected"; class myPromise { constructor(executor) { this.status = PENDING; // 聲明初始狀態; this.value = undefined; // fulfilled狀態時 返回的信息 this.reason = undefined; // rejected狀態時 拒絕的緣由; this.onFulfilledCallbacks = []; // 存儲fulfilled狀態對應的onFulfilled函數 this.onRejectedCallbacks = []; // 存儲rejected狀態對應的onRejected函數 //=>執行Excutor let resolve = result => { // resolve方法 if (this.status !== PENDING) return; // 爲何resolve 加setTimeout? // 2.2.4規範 onFulfilled 和 onRejected 只容許在 execution context 棧僅包含平臺代碼時運行. // 這裏的平臺代碼指的是引擎、環境以及promise的實施代碼。實踐中要確保onFulfilled 和 onRejected方法異步執行,且應該在then方法被調用的那一輪事件循環以後的新執行棧中執行。 setTimeout(() => { //只能由pending狀態=>fulfilled狀態(避免調用屢次resolve reject) this.status = FULFILLED; this.value = result; this.onFulfilledCallbacks.forEach(cb => cb(this.value)); }, 0); }; let reject = reason => { // reject方法 if (this.status !== PENDING) return; setTimeout(() => { this.status = REJECTED; this.reason = reason; this.onRejectedCallbacks.forEach(cb => cb(this.reason)) }) }; // 捕獲在executor執行器中拋出的異常 try { executor(resolveFn, rejectFn); } catch (err) { //=>有異常信息按照rejected狀態處理 reject(err); } } // 添加.then方法 then(onFullfilled, onRejected) { this.onFulfilledCallbacks.push(onFullfilled); this.onRejectedCallbacks.push(onRejected); } // 添加.catch方法 catch(onRejected) { return this.then(null, onRejected); } } module.exports = myPromise;
不過在面試中有些會要求手寫一個符合Promises/A+規範的完美Promise。app
首先來看下Promises規範:異步
Promise 規範有不少,如Promise/A,Promise/B,Promise/D 以及 Promise/A 的升級版 Promise/A+。ES6 中採用了Promise/A+ 規範。async
// promise 三個狀態 const PENDING = "pending"; const FULFILLED = "fulfilled"; const REJECTED = "rejected"; class myPromise { constructor(executor) { this.status = PENDING; // 聲明初始狀態; this.value = undefined; // fulfilled狀態時 返回的信息 this.reason = undefined; // rejected狀態時 拒絕的緣由; this.onFulfilledCallbacks = []; // 存儲fulfilled狀態對應的onFulfilled函數 this.onRejectedCallbacks = []; // 存儲rejected狀態對應的onRejected函數 //=>執行Excutor let resolve = result => { // resolve方法 if (this.status !== PENDING) return; // 爲何resolve 加setTimeout? // 2.2.4規範 onFulfilled 和 onRejected 只容許在 execution context 棧僅包含平臺代碼時運行. // 這裏的平臺代碼指的是引擎、環境以及promise的實施代碼。實踐中要確保onFulfilled 和 onRejected方法異步執行,且應該在then方法被調用的那一輪事件循環以後的新執行棧中執行。 setTimeout(() => { //只能由pending狀態=>fulfilled狀態(避免調用屢次resolve reject) this.status = FULFILLED; this.value = result; this.onFulfilledCallbacks.forEach(cb => cb(this.value)); }, 0); }; let reject = reason => { // reject方法 if (this.status !== PENDING) return; setTimeout(() => { this.status = REJECTED; this.reason = reason; this.onRejectedCallbacks.forEach(cb => cb(this.reason)) }) }; // 捕獲在executor執行器中拋出的異常 try { executor(resolveFn, rejectFn); } catch (err) { //=>有異常信息按照rejected狀態處理 reject(err); } } // 添加.then方法 then(onFullfilled, onRejected) { onFullfilled = typeof onFullfilled === "function" ? onFullfilled : value => value; onRejected = typeof onRejected === "function" ? onRejected : reason => { throw reason; }; switch (self.status) { case PENDING: // 當異步調用resolve/rejected時 將onFulfilled/onRejected收集暫存到集合中 return promise2 = new myPromise((resolve, reject) => { this.onFulfilledCallbacks.push(()=>{ try { let x = onFullfilled(this.value); this.resolvePromise(promise2, x, resolve, reject); // 新的promise resolve 上一個onFulfilled的返回值 } catch (e) { reject(e); // 捕獲前面onFulfilled中拋出的異常 then(onFulfilled, onRejected); } }); this.onRejectedCallbacks.push(() => { try { let x = onRejected(this.reason); this.resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); // error catch } }); }); break; case FULFILLED: return promise2 = new myPromise(function (resolve, reject) { try { let x = onFullfilled(this.value); //將上次一then裏面的方法傳遞進下一個Promise狀態 this.resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e);//error catch } }); break; case REJECTED: return promise2 = new myPromise(function (resolve, reject) { try { let x = onRejected(this.reason); //將then裏面的方法傳遞到下一個Promise的狀態裏 this.resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }); break; default: } } // 添加.catch方法 catch(onRejected) { return this.then(null, onRejected); } static deferred() { // 延遲對象 let defer = {}; defer.promise = new myPromise((resolve, reject) => { defer.resolve = resolve; defer.reject = reject; }); return defer; } static all(promises = []) { let index = 0, result = []; return new Promise((resolve, reject) => { for (let i = 0; i < promises.length; i++) { promises[i].then(val => { index++; result[i] = val; if (index === promises.length) { resolve(result) } }, reject); } }) } static resolvePromise(promise, x, resolve, reject) { if (promise === x) { // 若是從onFulfilled中返回的x 就是promise2 就會致使循環引用報錯 throw new TypeError("type error") } let isUsed; if (x !== null && (x instanceof Object || x instanceof Function)) { try { let then = x.then; if (typeof then === "function") { //是一個promise的狀況 then.call(x,(y) => { if (isUsed) return; isUsed = true; this.resolvePromise(promise, y, resolve, reject); },(e) => { if (isUsed) return; isUsed = true; reject(e); }) } else { //僅僅是一個函數或者是對象 resolve(x) } } catch (e) { if (isUsed) return; isUsed = true; reject(e); } } else { //返回的基本類型,直接resolve resolve(x) } } } module.exports = myPromise;
npm i -g promises-aplus-tests promises-aplus-tests Promise.js
promise的原理Promise/A+的實現就結束了。
栗子:
function sleep(wait) { return new Promise((res,rej) => { setTimeout(() => { res(wait); },wait); }); } async function demo() { let result01 = await sleep(100); //上一個await執行以後纔會執行下一句 let result02 = await sleep(result01 + 100); let result03 = await sleep(result02 + 100); // console.log(result03); return result03; } demo().then(result => { console.log(result); });
異步編程的最高境界,根本就不用關心它異步,不少人認爲它是異步操做的終極解決方案;可是和 Promise不存在誰取代誰,由於 async/await是寄生於 Promise。 Generator的語法糖。
對Generator還比較陌生的同窗能夠看下廖雪峯寫的generator,這裏就不作過多介紹了。
async/await語法糖就是使用Generator函數+自動執行器來運做的。 咱們能夠參考如下例子
// 定義了一個promise,用來模擬異步請求,做用是傳入參數++ function getNum(num){ return new Promise((resolve, reject) => { setTimeout(() => { resolve(num+1) }, 1000) }) } //自動執行器,若是一個Generator函數沒有執行完,則遞歸調用 function asyncFun(func){ var gen = func(); function next(data){ var result = gen.next(data); if (result.done) return result.value; result.value.then(function(data){ next(data); }); } next(); } // 所須要執行的Generator函數,內部的數據在執行完成一步的promise以後,再調用下一步 var func = function* (){ var f1 = yield getNum(1); var f2 = yield getNum(f1); console.log(f2) ; }; asyncFun(func);
在執行的過程當中,判斷一個函數的promise是否完成,若是已經完成,將結果傳入下一個函數,繼續重複此步驟。
若是發現過程遇到什麼問題,歡迎及時提出