在javascript的世界中,全部代码都是单线程执行的。因为这个“缺陷”,致使JavaScript的全部网络操做,浏览器事件,都必须是异步执行。 最开始咱们能够用回调函数来解决这个问题,javascript
function callBack(){
console.log('回调')
}
setTimeout(callBack, 1000)
// 回调
复制代码
可是随着业务的不断深刻,不免会像陷入回调地狱这样的问题。直到后来咱们有了Promise来解决这个问题。html
promise的基本用法以下: 在实例化一个Promise时,传入一个函数做为参数,该函数接受两个参数,分别为resolve,reject.如解决则会打印数据,如被拒绝则会打印拒绝缘由java
let p1 = new Promise(function (resolve, reject) {
})
p1.then(function (data) {
console.log(data)
}, function (err) {
console.log(err)
})
复制代码
3.状态机制切换 如图所示,状态只能由pengding-->fulfilled,或者由pending-->rejected这样转变。 只要这两种状况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对Promise对象添加回调函数,也会当即获得这个结果。这与事件(Event)彻底不一样,事件的特色是,若是你错过了它,再去监听,是得不到结果的 数组
function Promise(executor) {
this.state = 'pending'; //状态
this.value = undefined; //成功结果
this.reason = undefined; //失败缘由
function resolve(value) { }
function reject(reason) { }
executor(resolve, reject) //当即执行
}
复制代码
接收一个executor函数,executor函数传入就执行(当咱们示例化一个promise时,executor当即执行),执行完同步或异步操做后,调用它的两个参数resolve和reject。其中state保存了promise的状态,包含三个状态:等待态(pending)成功态(resolved)和失败态(rejected)。promise执行成功后的结果由value保存,失败后的缘由由reason保存。promise
function Promise(executor) {
this.state = 'pending'; //状态
this.value = undefined; //成功结果
this.reason = undefined; //失败缘由
resolve = (value) => {
// state改变,resolve调用就会失败
if (this.state === 'pending') {
// resolve调用后,state转化为成功态
this.state = 'fulfilled';
// 储存成功的值
this.value = value;
}
}
reject = (reason) => {
// state改变,reject调用就会失败
if (this.state === 'pending') {
// reject调用后,state转化为失败态
this.state = 'rejected';
// 储存失败的缘由
this.reason = reason;
}
}
//若是executor执行报错,直接执行reject
try {
executor(resolve, reject)
} catch (err) {
reject(err) // executor出错就直接调用
}
}
复制代码
每个Promise实例都有一个then方法,接收两个为函数的参数,它用来处理异步返回的结果,它是定义在原型上的方法。浏览器
Promise.prototype.then = function (onFulfilled, onRejected) {
};
复制代码
当promise的状态发生了变化,不论成功或失败都会调用then方法,所以then方法里面也会根据不一样的状态来判断调用哪个回调函数。 两个参数的注意事项:网络
Promise.prototype.then = function (onFulfilled, onRejected) {
if (this.state === 'fulfilled') {
//判断参数类型,是函数执行之,若是 onFulfilled 不是函数,其必须被忽略
if (typeof onFulfilled === 'function') {
onFulfilled(this.value); // 传入成功的值
}
}
// 若是 onRejected 不是函数,其必须被忽略
if (this.state === 'rejected') {
if (typeof onRejected === 'function') {
onRejected(this.reason); // 传入失败的缘由
}
}
};
复制代码
上述把promise的基本功能都实现了,可是仍是会存在一个问题,就是promise不支持异步代码,当resolve或reject在setTimeout中实现时,调用then方法时,此时状态仍然是pengding,then方法即没有调用onFulfilled也没有调用onRejected,也就运行没有任何结果。异步
咱们能够参照发布订阅模式,在执行then方法时状态仍是状态仍是pengding时,把回调函数存储在一个数组中,当状态发生改变时依次从数组中取出执行就行了,首先在类上新增两个Array类型的数组,用于存放回调函数。函数
function Promise(executor) {
this.state = 'pending'; //状态
this.value = undefined; //成功结果
this.reason = undefined; //失败缘由
this.onFulfilledFunc = [];//保存成功回调
this.onRejectedFunc = [];//保存失败回调
function resolve(value) {
// ....
}
function reject(reason) {
// ....
}
executor(resolve, reject) //当即执行
}
复制代码
并修改then方法post
Promise.prototype.then = function (onFulfilled, onRejected) {
if (this.state === 'pending') {
if (typeof onFulfilled === 'function') {
this.onFulfilledFunc.push(onFulfilled);//保存回调
}
if (typeof onRejected === 'function') {
this.onRejectedFunc.push(onRejected);//保存回调
}
}
if (this.state === 'fulfilled') {
//判断参数类型,是函数执行之,若是 onFulfilled 不是函数,其必须被忽略
if (typeof onFulfilled === 'function') {
onFulfilled(this.value); // 传入成功的值
}
}
// 若是 onRejected 不是函数,其必须被忽略
if (this.state === 'rejected') {
if (typeof onRejected === 'function') {
onRejected(this.reason); // 传入失败的缘由
}
}
};
复制代码
修改resolve和reject方法:
function Promise(executor) {
// 其余代码
function resolve(value) {
// state改变,resolve调用就会失败
if (this.state === 'pending') {
// resolve调用后,state转化为成功态
this.state = 'fulfilled';
// 储存成功的值
this.value = value;
this.onFulfilledFunc.forEach(fn => fn(value))
}
}
function reject(reason) {
// state改变,reject调用就会失败
if (this.state === 'pending') {
// reject调用后,state转化为失败态
this.state = 'rejected';
// 储存失败的缘由
this.reason = reason;
this.onRejectedFunc.forEach(fn => fn(reason))
}
}
// 其余代码
}
复制代码
到这里Promise已经支持了异步操做了。
光是实现了异步操做可不行,咱们经常用到new Promise().then().then()这样的链式调用来解决回调地狱。 规范如何定义then方法:
Promise.prototype.then = function (onFulfilled, onRejected) {
let promise2 = new Promise((resolve, reject) => {
// 其余代码
}
return promise2;
};
复制代码
接下来就处理根据上一个then方法的返回值来生成新Promise对象.
/** * 解析then返回值与新Promise对象 * @param {Object} promise2 新的Promise对象 * @param {*} x 上一个then的返回值 * @param {Function} resolve promise2的resolve * @param {Function} reject promise2的reject */
function resolvePromise(promise2, x, resolve, reject) {
//...
}
复制代码
当then的返回值与新生成的Promise对象为同一个(引用地址相同),状态永远为等待态(pending),再也没法成为resolved或是rejected,程序会死掉,则会抛出TypeError错误
let promise2 = p.then(data => {
return promise2;
});
// TypeError: Chaining cycle detected for promise #<Promise>
复制代码
所以须要判断x。
小提示: 为何取对象上的属性有报错的可能?Promise有不少实现(bluebird,Q等),Promises/A+只是一个规范,你们都按此规范来实现Promise才有可能通用,所以全部出错的可能都要考虑到,假设另外一我的实现的Promise对象使用Object.defineProperty()恶意的在取值时抛错,咱们能够防止代码出现Bug resolvePromise实现
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) { // 1.x不能等于promise2
reject(new TypeError('Promise发生了循环引用'));
}
let called;
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
// 2. 多是个对象或是函数
try {
let then = x.then;// 3.取出then方法引用
if (typeof then === 'function') { // 此时认为then是一个Promise对象
//then是function,那么执行Promise
then.call(x, (y) => { // 5.使用x做为this来调用then方法,即then里面的this指向x
if (called) return;
called = true;
// 6.递归调用,传入y如果Promise对象,继续循环
resolvePromise(promise2, y, resolve, reject);
}, (r) => {
if (called) return;
called = true;
reject(r);
});
} else {
resolve(x);
}
} catch (e) {
// 也属于失败
if (called) return;
called = true;
reject(e); // 4.取then报错,直接reject
}
} else {
//不然是个普通值
resolve(x);
}
}
复制代码
此时链式调用支持已经实现,在相应的地方调用resolvePromise方法便可。
规范还对onFulfilled和onRejected有规定
完善then方法
Promise.prototype.then = function (onFulfilled, onRejected) {
let promise2 = new Promise((resolve, reject) => {
// onFulfilled若是不是函数,就忽略onFulfilled,直接返回value
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
// onRejected若是不是函数,就忽略onRejected,直接扔出错误
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
if (this.state === 'pending') {
this.onFulfilledFunc.push(() => {
// 异步
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
})
this.onRejectedFunc.push(() => {
// 异步
setTimeout(() => {
try {
let x = onRejected(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
})
}
if (this.state === 'fulfilled') {
// 异步
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.state === 'rejected') {
// 异步
setTimeout(() => {
// 若是报错
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
})
return promise2;
};
复制代码
到这里手写一个Promise已经所有实现了 完整代码
function Promise(executor) {
this.state = 'pending'; //状态
this.value = undefined; //成功结果
this.reason = undefined; //失败缘由
this.onFulfilledFunc = [];//保存成功回调
this.onRejectedFunc = [];//保存失败回调
resolve = (value) => {
// state改变,resolve调用就会失败
if (this.state === 'pending') {
// resolve调用后,state转化为成功态
this.state = 'fulfilled';
// 储存成功的值
this.value = value;
this.onFulfilledFunc.forEach(fn => fn(value))
}
}
reject = (reason) => {
// state改变,reject调用就会失败
if (this.state === 'pending') {
// reject调用后,state转化为失败态
this.state = 'rejected';
// 储存失败的缘由
this.reason = reason;
this.onRejectedFunc.forEach(fn => fn(reason))
}
}
//若是executor执行报错,直接执行reject
try {
executor(resolve, reject)
} catch (err) {
reject(err) // executor出错就直接调用
}
}
Promise.prototype.then = function (onFulfilled, onRejected) {
let promise2 = new Promise((resolve, reject) => {
// onFulfilled若是不是函数,就忽略onFulfilled,直接返回value
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
// onRejected若是不是函数,就忽略onRejected,直接扔出错误
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
if (this.state === 'pending') {
this.onFulfilledFunc.push(() => {
// 异步
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
})
this.onRejectedFunc.push(() => {
// 异步
setTimeout(() => {
try {
let x = onRejected(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
})
}
if (this.state === 'fulfilled') {
// 异步
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.state === 'rejected') {
// 异步
setTimeout(() => {
// 若是报错
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
})
return promise2;
};
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
reject(new TypeError('Promise发生了循环引用'));
}
let called;
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
//多是个对象或是函数
try {
let then = x.then;//取出then方法引用
if (typeof then === 'function') { // 认为then是一个Promise对象
//then是function,那么执行Promise
then.call(x, (y) => {
// 成功和失败只能调用一个
if (called) return;
called = true;
//递归调用,传入y如果Promise对象,继续循环
resolvePromise(promise2, y, resolve, reject);
}, (r) => {
// 成功和失败只能调用一个
if (called) return;
called = true;
reject(r);
});
} else {
resolve(x);
}
} catch (e) {
// 也属于失败
if (called) return;
called = true;
reject(e);
}
} else {
//不然是个普通值
resolve(x);
}
}
复制代码
可是只用构造函数实现固然是不够的,咱们再用class来实现一个Promise,基本原理同上 class实现
class Promise {
constructor(executor) {
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onResolvedCallbacks.forEach(fn => fn());
}
};
let reject = reason => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn => fn());
}
};
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
let promise2 = new Promise((resolve, reject) => {
if (this.state === 'fulfilled') {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.state === 'rejected') {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.state === '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;
}
catch(fn) {
return this.then(null, fn);
}
}
function resolvePromise(promise2, x, resolve, reject) {
if (x === promise2) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
let called;
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
try {
let then = x.then;
if (typeof then === 'function') {
then.call(x, y => {
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject);
}, err => {
if (called) return;
called = true;
reject(err);
})
} else {
resolve(x);
}
} catch (e) {
if (called) return;
called = true;
reject(e);
}
} else {
resolve(x);
}
}
//resolve方法
Promise.resolve = function (val) {
return new Promise((resolve, reject) => {
resolve(val)
});
}
//reject方法
Promise.reject = function (val) {
return new Promise((resolve, reject) => {
reject(val)
});
}
//race方法
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(resolve, reject)
};
})
}
//all方法(获取全部的promise,都执行then,把结果放到数组,一块儿返回)
Promise.all = function (promises) {
let arr = [];
let i = 0;
function processData(index, data) {
arr[index] = data;
i++;
if (i == promises.length) {
resolve(arr);
};
};
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(data => {
processData(i, data);
}, reject);
};
});
}
复制代码
开源社区提供了一个包用于测试咱们的代码:promises-aplus-tests,安装这个包而后运行命令行 promises-aplus-tests [js文件名] 便可验证。别忘了再代码后面加上这一段代码
// 目前是经过他测试 他会测试一个对象
// 语法糖
Promise.defer = Promise.deferred = function () {
let dfd = {}
dfd.promise = new Promise((resolve,reject)=>{
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
}
module.exports = Promise;
复制代码
参考连接