概述
Promise最早由社区提出并实现,典型的一些库有Q,when, bluebird等;它们的出现是为了更好地解决JavaScript中异步编程的问题,传统的异步编程最大的特点就是地狱般的回调嵌套,一旦嵌套次数过多,就很容易使我们的代码难以理解和维护。而Promise则可以让我们通过链式调用的方法去解决回调嵌套的问题,使我们的代码更容易理解和维护,而且Promise还增加了许多有用的特性,让我们处理异步编程得心应手
Promise创建
Promise本意是承诺,它有三个状态(等待态、成功态、失败态), 默认是等待态。new Promise 时传递一个执行器 (executor),且执行器立即执行
//Promise是一个类
console.log(2)
new Promise(function ((resolve, reject) => {
console.log(1)
))
console.log(3);
输出结果如下:
2
1
3
复制代码
Promise.then
每个promise实例都一个then方法,then方法有两个参数(成功和失败),成功会有成功的值,失败会有失败的原因
let promise = new Promise((resolve, reject) => {
//resolve('hello');
reject('hello')
});
promise.then(data => {
console.log('data', data);
}, err=>{
console.log('err', err)
})
输出结果如下:
//data hello
err hello
复制代码
且同一个promise可以then多次
let promise = new Promise((resolve, reject) => {
//resolve('hello');
reject('hello')
});
promise.then(data => {
console.log('data', data);
}, err=>{
console.log('err', err)
});
promise.then(data => {
console.log('data', data);
}, err=>{
console.log('err', err)
})
输出结果如下:
//data hello
//data hello
err hello
err hello
复制代码
基本的promise实现
Promise/A+ 规范的内容比较多,详情查看promisesaplus.com/,实现 Promise 逻辑时会根据实现的部分介绍相关的Promise/A+规范内容。
class Promise {
constructor(executor) {
//默认的状态
this.status = 'pending';
//成功的值
this.value = undefined;
//失败的原因
this.reason = undefined;
//成功存放的数组
this.onResolvedCallbacks = [];
//失败存放的数组
this.onRejectedCallbacks = [];
//默认让执行器执行
let resolve = (value) => {
if (this.status === 'pending') {
this.status = 'fulfilled'; //成功
this.value = value;
this.onResolvedCallbacks.forEach(fn => fn());
}
}
let reject = (reason) => {
if (this.status === 'pending') {
this.status = 'rejected'; //失败
this.reason = reason;
this.onRejectedCallbacks.forEach(fn => fn());
}
}
try{
executor(resolve, reject);
}catch(e) {
reject(e);
}
}
then(onFufilled, onRejected) {
if (this.status === 'fulfilled') {
onFufilled(this.value);
}
if (this.status === 'rejected') {
onRejected(this.reason);
}
if (this.status === 'pending') {
this.onResolvedCallbacks.push(() => {
onFufilled(this.value);
});
this.onRejectedCallbacks.push(() => {
onRejected(this.reason);
})
}
}
}
module.exports = Promise;
复制代码
验证实现的promise
example 1
let Promise = require('./Promise.js')
let promise = new Promise((resolve, reject) => {
resolve('hello')
});
promise.then(data => {
console.log('data', data);
}, err=>{
console.log('err', err)
});
输出结果如下
data hello
example 2
let Promise = require('./Promise.js')
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('hello')
})
});
promise.then(data => {
console.log('data', data);
}, err=>{
console.log('err', err)
});
输出结果如下
data hello
复制代码
Promise链式调用
- Promise内部抛出异常,直接走失败执行函数
let fs = require('fs');
function read (path, enconding) {
return new Promise((resolve, reject) => {
throw new Error('内部抛出异常');
fs.readFile(path, enconding, (err, data) => {
if (err) reject(err);
resolve(data);
})
})
}
read('./3.txt', 'utf8').then(data => {
console.log(data);
}, err => {
console.log("error", err)
})
输出结果如下:
error Error: 内部抛出异常
复制代码
- Promise解决多个异步回调(有关联)
//成功的回调,或者失败的回调执行后返回一个promise
//会将这个promise的结果传给下一个then中
//如果返回普通值,会将这个普通值传递到下一次then的成功参数
read('./1.txt', 'utf8').then(data => {
console.log('then1', data)
return read(data, 'utf8');
}, err => {
console.log("err1", err)
}).then(data => {
console.log('then2', data);
}, err => {
console.log("err2", err)
});
注: 1.txt 文本内容为 "2.txt"
2.txt 文本内容为 "数据"
输出结果如下:
then1 2.txt
then2 数据
read('./1.txt', 'utf8').then(data => {
console.log('then1', data)
return read(data, 'utf8');
}, err => {
console.log("err1", err)
}).then(data => {
console.log('then2', data);
return data
}, err => {
console.log("err2", err)
}).then(data => {
console.log('then3', data)
}).then(data => {
console.log('then4', data)
});
输出结果如下:
then1 2.txt
then2 数据
then3 数据
then4 undefined
read('./1.txt', 'utf8').then(data => {
console.log('then1', data)
return read(data, 'utf8');
}, err => {
console.log("err1", err)
}).then(data => {
console.log('then2', data);
return data
}, err => {
console.log("err2", err)
}).then(data => {
console.log('then3', data)
}).then(data => {
console.log('then4', data);
throw new Error('xxxxxxxxxxxxxxxx');
}).then(null, err => {
console.log("err5", err)
}).then(data => {
console.log('then5 成功', data)
}, err=> {
console.log("err6 失败")
})
输出结果如下
then1 2.txt
then2 数据
then3 数据
then4 undefined
err5 Error: xxxxxxxxxxxxxxxx
then5 成功 undefined
read('./1.txt', 'utf8').then(data => {
console.log('then1', data)
return read(data, 'utf8');
}, err => {
console.log("err1", err)
}).then(data => {
console.log('then2', data);
return data
}, err => {
console.log("err2", err)
}).then(data => {
console.log('then3', data)
}).then(data => {
console.log('then4', data);
throw new Error('xxxxxxxxxxxxxxxx');
}).then().then(data => {
console.log('then5 成功', data)
}).catch(err => {
console.log("catch", err)
})
输出结果如下
then1 2.txt
then2 数据
then3 数据
then4 undefined
catch Error: xxxxxxxxxxxxxxxx
复制代码
- Promise解决多个异步回调(无关联)
Promise.all 多个promise都成功后,执行成功回调,如果有一个失败,走失败回调
let fs = require('fs');
function read(path, enconding) {
return new Promise((resolve, reject) => {
fs.readFile(path, enconding, (err, data) => {
if (err) reject(err);
resolve(data);
})
})
}
let pRead1 = read('./1.txt', 'utf-8');
let pRead2 = read('./2.txt', 'utf-8');
Promise.all([pRead1, pRead2]).then(res => {
console.log(res);
})
输出结果如下
[ '2.txt', '数据 ' ]
复制代码
Promise.race,多个promise执行,谁先执行完,就用先执行的结果
let fs = require('fs');
function read(path, enconding) {
return new Promise((resolve, reject) => {
fs.readFile(path, enconding, (err, data) => {
if (err) reject(err);
resolve(data);
})
})
}
let pRead1 = read('./1.txt', 'utf-8');
let pRead2 = read('./2.txt', 'utf-8');
Promise.race([pRead2, pRead1]).then(res => {
console.log(res);
}, err => {
console.log('err', err)
})
输出结果如下
2.txt
复制代码
- Promise.resolve、Promise.reject
Promise.resolve(123).then(data => {
console.log(data)
});
Promise.reject('err 123').then(null, err => {
console.log(err)
})
复制代码
实现Promise链式调用(promise实现链式调用返回一个新的promise)
class Promise {
constructor(executor) {...}
then(onFufilled, onRejected) {
onFufilled = typeof onFufilled === 'function' ? onFufilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : err => {throw err;};
let promise2;
promise2 = new Promise((resolve, reject) => {
if (this.status === 'fulfilled') {
setTimeout(() => {
try{
let x = onFufilled(this.value);
resolvePromise(promise2, x, resolve, reject);
}catch(e) {
reject(e)
}
}, 0);
}
if (this.status === 'rejected') {
setTimeout(() => {
try{
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
}catch(e) {
reject(e)
}
}, 0);
}
if (this.status === 'pending') {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try{
let x = onFufilled(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;
//将每个 Promise 实例调用 then 后返回的新 Promise 实例称为 promise2,将 then 回调返回的值称为 x;
}
}
function resolvePromise(promise2, x, resolve, reject) {
/*
如果 promise2 和 x 为同一个对象,由于 x 要将执行成功或失败的结果传递 promise2 的 then 方法回调的参数,
因为是同一个 Promise 实例,此时既不能成功也不能失败(自己不能等待自己完成),造成循环引用,
这种情况下规定应该抛出一个类型错误来回绝;
*/
if (promise2 === x) {
return reject(new TypeError('循环引用'))
}
let called;
//如果 x 是一个对象或者函数且不是 null
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
/*
如果 x 是对象,防止 x 是通过 Object.defineProperty 添加 then 属性,并添加 get 和 set 监听,
如果在监听中抛出异常,需要被捕获到
*/
try{
let then = x.then //如果是对象,试着取下then
if (typeof then === 'function') {
//x.then 是一个函数,就当作 x 是一个 Promise 实例,
then.call(x, y => {
if (called) return;
called = true;
//resolve的结果依旧是promise,继续解析
resolvePromise(promise2, y, resolve, reject);
}, r => {
if (called) return;
called = true;
reject(y);
})
}else {
//如果 x.then 不是函数,则说明 x 为普通值,直接调用 promise2 的 resolve 方法将 x 传入,
resolve(x);
}
}catch(e) { //取then出错,不在继续执行
if (called) return;
called = true;
reject(e);
}
}else {
//不满足条件说明该返回值就是一个普通值,直接执行 promise2 的 resolve 并将 x 作为参数传入;
resolve(x);
}
}
module.exports = Promise;
复制代码
验证promise链式调用
let Promise = require('./Promise')
let promise = new Promise((resolve, reject) => {
resolve('hello');
})
promise.then(data => {
console.log('then1', data);
return 4
}).then(data => {
console.log("data", data)
}).then(() => {
throw new Error("error");
}).then(() => {
console.log("success");
}, err => {
console.log(err);
}).then(() => {
console.log("成功");
}, () => {
console.log("失败");
});
输出结果如下
then1 hello
data 4
Error: error
成功
复制代码
验证参数是否穿透
let p1 = new Promise((resolve, reject) => resolve("ok"));
let p2 = p1.then().then(data => {
console.log(data);
throw new Error("出错了");
});
p2.then().then(null, err => console.log(err));
输出结果如下
ok
Error: 出错了
复制代码
实现catch方法
class Promise {
constructor(executor) {...}
then(onFufilled, onRejected) {...}
catch(onRejected) {
return this.then(null, onRejected)
}
}
复制代码
实现Promise.resolve方法
Promise.resolve = function (value) {
return new Promise((resolve, reject) => {
resolve(value);
})
}
复制代码
实现Promise.reject方法
Promise.reject = function (reason) {
return new Promise((resolve, reject) => {
reject(reason);
})
}
复制代码
实现Promise.all方法
Promise.all = function (promises) {
return new Promise((resolve, reject) => {
let result = [];
let idx = 0;
let processData = (index, data) => {
idx++;
result[index] = data;
if (promises.length === idx) {
resolove(result)
}
}
for (let i = 0; i < promises.length; i++) {
promises[i].then(data => {
processData(i, data);
}, reject)
}
})
}
复制代码
实现Promise.race方法
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(resolve, reject)
}
})
}
复制代码
测试Promise的实现代码(测试包 promises-aplus-tests)
- 全局安装 npm install promises-aplus-tests -g
Promise.defer = Promise.deferred = function () {
let dfd = {};
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
}
//https://www.pandashen.com/2018/06/13/20180613193626/#more <-- 更多描述请查看
复制代码