什么是Promise
Promise 是一个构造函数, new Promise 返回一个 promise对象 接收一个excutor执行函数作为参数, excutor有两个函数类型形参resolve reject
其用法是let p = new Promise(function (resolve,reject){
resolve("这是promise")
reject("这个不执行")
})
p.then(function (data) {
console.log(data)
},function (err) {
console.log(err)
})复制代码
开始写一个Promise
1,我们从用法中就可以看出new Promise里面是一个函数,而函数里的传参是两个函数-resolve和reject。要明白,promise执行的时候有三种状态:
- pending
- resolve(成功)
- reject(失败)
只要成功就不会失败,只要失败就不会成功,不会又成功又失败。走了resolve就不会走reject,写了也没用。promise规范
function Promise(executor) {
let _self = this;
_self.status = "pending";
_self.value = undefined;//成功的原因;
_self.reason = undefined;//失败的原因;
function resolve(value) {
if(_self.status === "pending"){
_self.status = "resolved" //改变状态值
_self.value = value //给参数赋值
}
};
function reject(reason) {
_self.status = "rejected"
_self.reason = reason
}
try{ //捕获异常
executor(resolve,reject); //promise 参数是一个函数,函数中的俩个参数是两个函数
}catch (e){
reject(e)
}
}
//promise实例上有个then方法。
Promise.prototype.then = function (onFulfilled,onRejected) {
let _sele = this;
if(_sele.status === "resolved"){
onFulfilled(_sele.value)
}
if(_sele.status === "rejected"){
onRejected(_sele.reason)
}
}
module.exports = Promise;复制代码
一个简单的promise模块就写好了引入运行一下
let Promise = require('./promise')
let p = new Promise(function (resolve,reject){
resolve("这是promise")
})
p.then(function (data) {
console.log(data)
},function (err) {
console.log(err)
})复制代码
2,如果resolve 是需要异步执行,如下
let Promise = require('./promise')
let p = new Promise(function (resolve,reject){
setTimeout(function () { //给一个延迟
resolve("这是promise")
})
})
p.then(function (data) {
console.log(data)
},function (err) {
console.log(err)
})复制代码
这样的话执行结果是空,没有执行出来,因为我们类里写的then方法是同步执行,当执行到判断status的值的时候,因为setTimeout的原因,状态值还没改变过来,所以代码会一直停在那,所以我们在这种情况下就要给一个空间来存放这些没有状态的操作,当状态明确了再执行。那么听起来就需要给一个数组结构空间了。
function Promise(executor) {
let _self = this;
_self.status = "pending";
_self.value = undefined;//成功的原因;
_self.reason = undefined;//失败的原因;
_self.onResolvedCallbacks = []; // 存放then成功的回调
_self.onRejectedCallbacks = []; // 存放then失败的回调
function resolve(value) { // 成功状态
if(_self.status === "pending"){
_self.status = "resolved";
_self.value = value;
//判断好了状态,要循环执行出来,这里为什么会是数组,是因为会有:p.then();p.then(),多次执行的状态,不过只要有一个成功就是成功
_self.onResolvedCallbacks.forEach(function (fn) {
fn()
})
}
};
function reject(reason) { // 失败状态
_self.status = "rejected";
_self.reason = reason;
_self.onRejectedCallbacks.forEach(function (fn) {
fn()
})
}
try{
executor(resolve,reject);
}catch (e){ // 捕获的时候发生异常,就直接失败了
reject(e)
}
}
//promise实例上有个then方法。
Promise.prototype.then = function (onFulfilled,onRejected) {
let _sele = this;
if(_sele.status === "resolved"){
onFulfilled(_sele.value)
}
if(_sele.status === "rejected"){
onRejected(_sele.reason)
}
if(_sele.status === "pending"){
//把这个状态的都保存起来
_sele.onResolvedCallbacks.push(function () {
onFulfilled(_sele.value)
})
_sele.onRejectedCallbacks.push(function () {
onRejected(_sele.reason)
})
}
}
module.exports = Promise;复制代码
3,链式调用,promise可以实现链式调用。方便又实惠。执行代码如下:
let promise = new Promise(function (resolve,reject) {
resolve(100)
})
//链式调用的特点,将第一次成功的返回值当成下一次回调函数的参数
promise.then(function (data) {
throw new Error("123")
},function () {
}).then(function (data) {
console.log(data);
},function(err){
console.log(err)
})
//链式调用:靠的是返回一个新的promise复制代码
但其实也可以这样写:
let p2 = promise.then(function (data) {
return data //这里返回的只要不是错误,下次走的还是成功,
},function () {
})
p2.then(function (data) {
console.log(data);
},function(err){
console.log(err)
})复制代码
这里不等价于(返回数据的化直接让下一次的promise 成功 如果返回的是promise就等待这个promise执行结果)
let p2 = promise.then(function (data) {
return new Promise(function (resolve,reject) {
resolve(data)
})
},function () {
})
p2.then(function (data) {
console.log(data);
},function(err){
console.log(err)
})复制代码
正确的执行结果应该是100,那么开始写吧,(重头戏)
function Promise(executor) {
let _self = this;
_self.status = "pending";
_self.value = undefined;//成功的原因;
_self.reason = undefined;//失败的原因;
_self.onResolvedCallbacks = []; // 存放then成功的回调
_self.onRejectedCallbacks = []; // 存放then失败的回调
function resolve(value) { // 成功状态
if(_self.status === "pending"){
_self.status = "resolved";
_self.value = value;
//判断好了状态,要循环执行出来,这里为什么会是数组,是因为会有:p.then();p.then(),多次执行的状态,不过只要有一个成功就是成功
_self.onResolvedCallbacks.forEach(function (fn) {
fn()
})
}
};
function reject(reason) { // 失败状态
_self.status = "rejected";
_self.reason = reason;
_self.onRejectedCallbacks.forEach(function (fn) {
fn()
})
}
try{
executor(resolve,reject);
}catch (e){ // 捕获的时候发生异常,就直接失败了
reject(e)
}
}
//处理返回结果
function resolvePromise(promise2,x,resolve,reject) {
//
if(promise2 === x){ //首先要判断返回的x不能跟原来的promise相等,如果是的话就是自己等待自己了!。
return reject(new TypeError("不能循环引用")); //这里应该报一个类型错误,有问题
}
let called; //表示是否调过
if(x !== null &&(typeof x ==='object'||typeof x ==='function')){ //判断返回的x是不是一个promise,promise应该是一个对象;这里要把null排除因为typeof null是object
try{
// 1,看看返回的这个对象或方法里有没有then方法
let then = x.then;//这里then可能是{then:1}
if(typeof then === 'function'){ //说明是一个promise
then.call(x,function (y) { //call是为了this指向x,
//2,再看是否被调用过
if(called) return ; //表示是否调用过成功或者失败
called = true;
// y可能还是一个promise,在去解析直到返回的是一个普通值
resolvePromise(promise2,y,resolve,reject)
},function (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实例上有个then方法。
Promise.prototype.then = function (onFulfilled,onRejected) {
let _sele = this;
//首先要先定义一个新的promise
let promise2;
if(_sele.status === "resolved"){
promise2 = new Promise(function (resolve,reject) {
setTimeout(function () { //为了测试时 效果统一 因为很多人的实现 onfufiled 和 onrejected是异步执行,为了保证测试统一 所以全部异步
try { //捕获异常
let x = onFulfilled(_sele.value) //声明一个x来接受返回值
resolvePromise(promise2,x,resolve,reject)
}catch (e){
reject(e)
}
})
})
}
if(_sele.status === "rejected"){
promise2 = new Promise(function (resolve,reject) {
setTimeout(function () { //为了测试时 效果统一 因为很多人的实现 onfufiled 和 onrejected是异步执行,为了保证测试统一 所以全部异步
try { //捕获异常
let x = onRejected(_sele.reason) //声明一个x来接受返回值
resolvePromise(promise2,x,resolve,reject)
}catch (e){
reject(e)
}
})
})
}
// 当调用then时可能没成功 也没失败
if(_sele.status === "pending"){
promise2 = new Promise(function (resolve,reject) {
//把这个状态的都保存起来
_sele.onResolvedCallbacks.push(function () {
setTimeout(function () {
try {
let x = onFulfilled(_sele.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
})
});
_sele.onRejectedCallbacks.push(function () {
setTimeout(function () {
try {
let x = onRejected(_sele.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
})
});
})
}
return promise2;
}
module.exports = Promise;复制代码
对于promise2 === x 什么情况下出现
var p2 = promise.then(function (data) {
return p2
},function () {
})
p2.then(function (data) {
console.log(data);
},function(err){
console.log(err)
})复制代码
4,如果有人这样执行代码也要考虑进去
let p2 = promise.then(function (data) {
return new Promise(function (resolve,reject) {
resolve(data)
})
},function () {
})
p2.then().then().then(function (data) {//多个then()空调用
console.log(data);
},function(err){
console.log(err)
})复制代码
那我们就要对类里then方法里的回调做判断了
if(_self.status === "pending"){function Promise(executor) {
let _self = this;
_self.status = "pending";
_self.value = undefined;//成功的原因;
_self.reason = undefined;//失败的原因;
_self.onResolvedCallbacks = []; // 存放then成功的回调
_self.onRejectedCallbacks = []; // 存放then失败的回调
function resolve(value) { // 成功状态
// value可能是别人的promise
if(value !==null&&(typeof value === 'object'||typeof value === 'function')){ //这种情况是为了判断 resolve(New promise)
return value.then(resolve,reject)
}
if(_self.status === "pending"){
_self.status = "resolved";
_self.value = value;
//判断好了状态,要循环执行出来,这里为什么会是数组,是因为会有:p.then();p.then(),多次执行的状态,不过只要有一个成功就是成功
_self.onResolvedCallbacks.forEach(function (fn) {
fn()
})
}
};
function reject(reason) { // 失败状态
_self.status = "rejected";
_self.reason = reason;
_self.onRejectedCallbacks.forEach(function (fn) {
fn()
})
}
try{
executor(resolve,reject);
}catch (e){ // 捕获的时候发生异常,就直接失败了
reject(e)
}
}
//处理返回结果
function resolvePromise(promise2,x,resolve,reject) {
if(promise2 === x){ //首先要判断返回的x不能跟原来的promise相等。
return reject(new TypeError("不能循环引用")); //这里应该报一个类型错误,有问题
}
let called; //表示是否调过
if(x !== null &&(typeof x ==='object'||typeof x ==='function')){ //判断返回的x是不是一个promise,promise应该是一个对象;这里要把null排除因为typeof null是object
try{
// 1,看看返回的这个对象或方法里有没有then方法
let then = x.then;//这里then可能是{then:1}
if(typeof then === 'function'){ //说明是一个promise
then.call(x,function (y) { //call是为了this指向x,
//2,再看是否被调用过
if(called) return ; //表示是否调用过成功或者失败
called = true;
// y可能还是一个promise,在去解析直到返回的是一个普通值
resolvePromise(promise2,y,resolve,reject)
},function (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实例上有个then方法。
Promise.prototype.then = function (onFulfilled,onRejected) {
//成功和失败默认不穿给一个函数
onFulfilled = typeof onFulfilled ==='function'?onFulfilled:function (value) {
return value
};
onRejected = typeof onRejected ==='function' ? onRejected :function (err) {
throw err
}
let _sele = this;
//首先要先定义一个新的promise
let promise2;
if(_sele.status === "resolved"){
promise2 = new Promise(function (resolve,reject) {
setTimeout(function () { //为了测试时 效果统一 因为很多人的实现 onfufiled 和 onrejected是异步执行,为了保证测试统一 所以全部异步
try { //捕获异常
let x = onFulfilled(_sele.value) //声明一个x来接受返回值
resolvePromise(promise2,x,resolve,reject)
}catch (e){
reject(e)
}
})
})
}
if(_sele.status === "rejected"){
promise2 = new Promise(function (resolve,reject) {
setTimeout(function () { //为了测试时 效果统一 因为很多人的实现 onfufiled 和 onrejected是异步执行,为了保证测试统一 所以全部异步
try { //捕获异常
let x = onRejected(_sele.reason) //声明一个x来接受返回值
resolvePromise(promise2,x,resolve,reject)
}catch (e){
reject(e)
}
})
})
}
// 当调用then时可能没成功 也没失败
if(_sele.status === "pending"){
promise2 = new Promise(function (resolve,reject) {
//把这个状态的都保存起来
_sele.onResolvedCallbacks.push(function () {
setTimeout(function () {
try {
let x = onFulfilled(_sele.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
})
});
_sele.onRejectedCallbacks.push(function () {
setTimeout(function () {
try {
let x = onRejected(_sele.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
})
});
})
}
return promise2;
}
module.exports = Promise;复制代码
好了,一个完整的promise写完了,同学们联系的时候一定要记得引入自己写的promise文件哦!
对于以上代码实现,我们可以通过一个promises-aplus-tests的库来验证是否达成规范要求
可以通过npm install -g promises-aplus-tests,使用时直接promises-aplus-tests 文件名即可。
在Promise类上的挂方法
实现promise类上的 call,catch,race,resolve,reject等方法
// 捕获错误的方法
Promise.prototype.catch = function (callback) {
return this.then(null, callback)
}
// 解析全部方法
// let arr = [];
// arr[1] = 100;
// console.log(arr.length)
Promise.all = function (promises) {
//promises是一个promise的数组
return new Promise(function (resolve, reject) {
let arr = []; //arr是最终返回值的结果
let i = 0; // 表示成功了多少次
function processData(index, y) {
arr[index] = y;
if (++i === promises.length) {
resolve(arr);
}
}
for (let i = 0; i < promises.length; i++) {
promises[i].then(function (y) {
processData(i, y)
}, reject)
}
})
}
// 只要有一个promise成功了 就算成功。如果第一个失败了就失败了
Promise.race = function (promises) {
return new Promise(function (resolve, reject) {
for (var i = 0; i < promises.length; i++) {
promises[i].then(resolve,reject)
//这里详细解释一下
//promise[i].then(function(data){
// resolve(data) //只接收一个resolve,因为他们同属于最外层的new promise。
// },reject)
}
})
}
// 生成一个成功的promise
Promise.resolve = function(value){
return new Promise(function(resolve,reject){
resolve(value);
})
}
// 生成一个失败的promise
Promise.reject = function(reason){
return new Promise(function(resolve,reject){
reject(reason);
})
}
Promise.defer = Promise.deferred = function () {
let dfd = {};
dfd.promise = new Promise(function (resolve, reject) {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd
}复制代码
用法如下
Promise.defer = Promise.deferred = function () {
let dfd = {};
dfd.promise = new Promise(function (resolve, reject) {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd
}
let Promise = require('./Promise');
function read() {
let defer = Promise.defer()
require('fs').readFile('./2.promise/1.txt', 'utf8', function (err, data) {
if(err) defer.reject(err);
defer.resolve(data);
})
return defer.promise;
}
read().then(function (data) {
console.log(data)
},function(err){
console.log(err);
})
复制代码