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是否完成,若是已经完成,将结果传入下一个函数,继续重复此步骤。
若是发现过程遇到什么问题,欢迎及时提出