Promise A+规范
下载地址PromiseA+
Promise是ES6中的内置类,用来管理异步编程,但是其兼容性很差。
从A+规范角度来讲,Promise有以下特点。
1.Promise必须是个
object或者function
2.必须具备then方法
搭建Promise主体
在new Promise的时候,如果不传递参数,浏览器会抛出一个异常,所以创建的Promise构造函数必须传递参数。且Promise也必须可以被new执行。
/*自定义Promise*/
function Promise(executor) {
if (!(self instanceof Promise)) throw new TypeError('undefined is not a promise!');
if (typeof executor !== "function") throw new TypeError('Promise resolver ' + executor + ' is not a function!');
}
new Promise的时候会立即执行executor函数。并且会传递resolve和reject两个方法。
形成了一个相互回调函数处理模式,把一个函数A作为值,传递到另外一个执行的函数B中,在B中可以把A执行。
(function(){
/*自定义Promise*/
function Promise(executor) {
if (!(self instanceof Promise)) throw new TypeError('undefined is not a promise!');
if (typeof executor !== "function") throw new TypeError('Promise resolver ' + executor + ' is not a function!');
executor(function resolve(result) {
}, function reject(reason) {
});
}
})();
let p1 = new Promise(function (resolve, reject) {
resolve('OK');
// reject('NO');
});
在Promise中根绝状态来辨别是成功还是失败,state为当前Promise的状态;
pending等待
fulfilled成功
rejected失败
(function(){
/*自定义Promise*/
function Promise(executor) {
var self = this,
change;
if (!(self instanceof Promise)) throw new TypeError('undefined is not a promise!');
if (typeof executor !== "function") throw new TypeError('Promise resolver ' + executor + ' is not a function!');
// 实例具备的属性
self.state = 'pending';
self.result = undefined;
// 改变状态的方法
change = function change(state, result) {
if (self.state !== 'pending') return;
self.state = state;
self.result = result;
};
//异常捕获
try {
executor(function resolve(result) {
change('fulfilled', result);
}, function reject(reason) {
change('rejected', reason);
});
} catch (err) {
change('rejected', err);
}
}
})();
Promise实例方法
Promise.prototype = {
constructor: Promise,
self: true,//判断是否为自己写的Promise
then: function (onFulfilled, onRejected) {},
catch: function () {}
};
then方法的实现
Promise的核心是then的实现,在执行then方法的时候有以下几种情况。
情况1:如果已经知道对应实例的状态是成功还是失败的,则创建一个“异步微任务”,后期执行
onFulfilled/onRejected
情况2:如果此时还不知道实例状态,就先把onFulfilled/onRejected存储起来,后期更改其状态,再通知方法执行即可“异步微任务”
基于queueMicrotask可以创建异步微任务,但是兼容性很差,所以这一版本用settimeout模拟异步微任务。
then: function (onFulfilled, onRejected) {
var self = this;
switch (self.state) {
case 'fulfilled':
setTimeout(function () {
onFulfilled(self.result);
}, 0);
break;
case 'rejected':
setTimeout(function () {
onRejected(self.result);
}, 0);
break;
default:
self.onFulfilledCallbacks.push(onFulfilled);
self.onRejectedCallbacks.push(onRejected);
}
}
相应的,Promise的change方法需要根据传递的数组进行处理。
// 实例具备的属性
self.state = 'pending';
self.result = undefined;
self.onFulfilledCallbacks = [];
self.onRejectedCallbacks = [];
// 改变状态的方法
change = function change(state, result) {
if (self.state !== 'pending') return;
self.state = state;
self.result = result;
var callbacks = state === 'fulfilled' ? self.onFulfilledCallbacks : self.onRejectedCallbacks,
i = 0,
len = callbacks.length,
callback;
if (callbacks.length > 0) {
setTimeout(function () {
for (; i < len; i++) {
callback = callbacks[i];
if (typeof callback === "function") callback(result);
}
}, 0);
}
};
至此,then的方法就实现了,但是现在的代码并不支持then链的调用,也就是说实例在调用then 后不能继续调用then。
每一次执行then方法,都会返回一个全新的Promise实例
状态:是由上一个then传入的onFulfilled/onRejected执行决定的
- 方法执行看返回值,如果返回的不是promise实例,则方法执行不报错,新实例状态就是fulfilled,并且return的结果是新实例的结果,反之执行报错则认为新实例是失败的,结果是报错原因
- 如果返回的也是一个promise实例,这样的话状态和结果直接影响了实例的状态和结果
// 验证是否为Promise实例「THENABLE」
function isPromise(x) {
if (x == null) return false;
if (/^(object|function)$/i.test(typeof x)) {
if (typeof x.then === "function") {
return true;
}
}
return false;
}
// 处理onFulfilled或者onRejected方法执行返回结果的处理
function handle(promiseNew, x, resolve, reject) {
if (x === promiseNew) throw new TypeError('Chaining cycle detected for promise #<Promise>');
if (isPromise(x)) {
try {
x.then(resolve, reject);
} catch (err) {
reject(err);
}
return;
}
// 返回值不是promise实例,而且执行没有报错,则promiseNew一定是成功的,x是它的结果
resolve(x);
}
then: function (onFulfilled, onRejected) {
var self = this,
promiseNew,
x;
promiseNew = new Promise(function (resolve, reject) {
// resolve & reject 可以设置返回的@TP「新promise实例」是成功还是失败以及结果等
// 但是执行哪个方法,由监听onFulfilled|onRejected方法报错以及返回值来决定
switch (self.state) {
case 'fulfilled':
setTimeout(function () {
try {
x = onFulfilled(self.result);
handle(promiseNew, x, resolve, reject);
} catch (err) {
reject(err);
}
}, 0);
break;
case 'rejected':
setTimeout(function () {
try {
x = onRejected(self.result);
handle(promiseNew, x, resolve, reject);
} catch (err) {
reject(err);
}
}, 0);
break;
default:
self.onFulfilledCallbacks.push(function (result) {
try {
x = onFulfilled(result);
handle(promiseNew, x, resolve, reject);
} catch (err) {
reject(err);
}
});
self.onRejectedCallbacks.push(function (reason) {
try {
x = onRejected(reason);
handle(promiseNew, x, resolve, reject);
} catch (err) {
reject(err);
}
});
}
});
return promiseNew;
},
在执行的过程中需要捕获异常,一旦抛出异常,直接返回reject。
在使用Promise的时候,如果then中的某个方法不设置,其默认具备“穿透性”,【顺延到下一个then中的同状态的方法】
if (typeof onFulfilled !== "function") {
onFulfilled = function onFulfilled(result) {
return result;
};
}
if (typeof onRejected !== "function") {
onRejected = function onRejected(reason) {
throw reason;
};
}
catch的实现
catch: function (onRejected) {
return this.then(null, onRejected);
}
Promise私有静态方法
// 普通对象:私有静态方法
Promise.resolve = function resolve() {};
Promise.reject = function reject() {};
Promise.all = function all() {};
Promise.resolve的实现
Promise.resolve返回一个状态成功的promise实例
Promise.resolve = function resolve(result) {
return new Promise(function (resolve) {
resolve(result);
});
};
Promise.reject的实现
Promise.reject返回一个状态失败的promise实例
Promise.reject = function reject(reason) {
return new Promise(function (_, reject) {
reject(reason);
});
};
Promise.all的实现
Promise.all返回一个全新的的promise实例,等待集合中所有的promise实例都成功,才算成功,结果是按照顺序依次存储集合中的每一项的结果。
- 如果某一项不是promise的实例,我们把它作为一个成功的promise实例即可。
- 如果集合中有一项是失败的,则实例就是失败的。
Promise.all = function all(promises) {
var promiseNew,
results = [],
n = 0;
if (!Array.isArray(promises)) throw new TypeError(promises + ' is not iterable');
// 控制集合中的每一项都是promise实例
promises = promises.map(function (promise) {
if (!isPromise(promise)) return Promise.resolve(promise);
return promise;
});
// 返回一个全新的promise实例
promiseNew = new Promise(function (resolve, reject) {
promises.forEach(function (promise, index) {
promise.then(function (result) {
// result存储的是当前迭代这一项的成功结果
n++;
results[index] = result;
// 都处理成功
if (n >= promises.length) resolve(results);
}).catch(function (reason) {
// 只要有一项失败,@AP就是失败
reject(reason);
});
});
});
return promiseNew;
};
以上就是实现兼容IE10的PromiseA+。