简介
本质为class类,使用
new promise((resolve,reject)=>{
})
promise在实例化的时候就在执行
- 缺点
首先,无法取消
Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
回调地狱
- 多层嵌套的问题。
- 每种任务的处理结果存在两种可能性(成功或失败),那么需要在每种任务执行结束后分别处理这两种可能性。 这两种问题在回调函数时代尤为突出。Promise 的诞生就是为了解决这两个问题。
Promise解决回调地狱
- 回调函数延迟绑定
new Promise('1.json').then(data => {
return readFilePromise('2.json')
});
回调函数不是直接声明的,而是在通过后面的 then 方法传入的,即延迟传入
- 返回值穿透
let x = readFilePromise('1.json').then(data => {
return readFilePromise('2.json')//这是返回的Promise
});
x.then(/* 内部逻辑省略 */)
根据 then 中回调函数的传入值创建不同类型的Promise, 然后把返回的 Promise 穿透到外层, 以供后续的调用。这里的 x 指的就是内部返回的 Promise,然后在 x 后面可以依次完成链式调用。
- 错误冒泡
readFilePromise('1.json').then(data => {
return readFilePromise('2.json');
}).then(data => {
return readFilePromise('3.json');
}).then(data => {
return readFilePromise('4.json');
}).catch(err => {
// xxx
})
面产生的错误会一直向后传递,被 catch 接收到,就不用频繁地检查错误了
-
Promise进入微任务执行 异步操作结束后会调用 resolve 方法,或者中途遇到错误调用 reject 方法,这两者都是作为微任务进入到 EventLoop 中
回调的过程是异步的,解决浪费 CPU 性能的问题
放到当前宏任务最后执行,即加入微任务中,解决了回调执行的实时性问题
源码介绍
class Promise {
constuctor(execute) {
this.state = 'pengding' //状态值
this.value = '' //成功值
this.reason = '' //失败值
this.onResolvedCallback = [] //存储成功的执行数组
this.onRejectedCallbacks = [] //存储失败的执行数组
function resolve(value) {
//状态只能改一次,状态凝固
if (this.state === 'pengding') {
this.state = 'fulfilled'
this.value = 'value'
this.onResolvedCallback.forEach(fn => fn())
}
}
function reject(value) {
//状态只能改一次,状态凝固
if (this.state === 'pengding') {
this.state = 'rejected'
this.value = 'value'
this.onRejectedCallbacks.forEach(fn => fn())
}
}
function resolvePromise(bridgePromise, x, resolve, reject) {
//如果x是一个promise
if (x instanceof MyPromise) {
// 拆解这个 promise ,直到返回值不为 promise 为止
if (x.status === PENDING) {
x.then(y => {
resolvePromise(bridgePromise, y, resolve, reject);
}, error => {
reject(error);
});
} else {
x.then(resolve, reject);
}
} else {
// 非 Promise普通值的话直接 resolve 即可
resolve(x);
}
}
//书写then方法
then(onFullfied, onRejected){
if (this.state === 'fulfilled') {
return bridgePromise = new MyPromise((resolve, reject) => {
try {
// 状态变为成功,会有相应的 self.value
let x = onFulfilled(this.value);
// 暂时可以理解为 resolve(x),后面具体实现中有拆解的过程
resolvePromise(bridgePromise, x, resolve, reject);
} catch (e) {
reject(e);
}
})
}
if (this.state === 'rejected') {
return bridgePromise = new MyPromise((resolve, reject) => {
try {
// 状态变为失败,会有相应的 self.error
let x = onRejected(this.reason);
resolvePromise(bridgePromise, x, resolve, reject);
} catch (e) {
reject(e);
}
});
}
if (this.state === 'pending') {
//将成功的时候需要干的事情
this.onResolvedCallback.push(() => {
onFulfilled(this.value) //使用闭包将每次的变量暂存下来,防止异步多次调用使用最后一次的数据
})
//将失败的时候要干的事,存起来
this.onRejectedCallbacks.push(() => {
onRejected(this.reason) //使用闭包将每次的变量暂存下来,防止异步多次调用使用最后一次的数据
})
}
}
//异常中断报错
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
}
// catch方法
Promise.prototype.catch = function (onRejected) {
return this.then(null, onRejected);
}
//Promise.resolve
Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))
//1.传参为一个 Promise, 则直接返回它
//2.传参为一个 thenable 对象,返回的 Promise 会跟随这个对象,`采用它的最终状态`作为`自己的状态`
//3.其他情况,直接返回以该值为成功状态的promise对象。
Promise.resolve = (param) => {
if (param instanceof Promise) return param;
return new Promise((resolve, reject) => {
if (param && param.then && typeof param.then === 'function') {
// param 状态变为成功会调用resolve,将新 Promise 的状态变为成功,反之亦然
param.then(resolve, reject);
} else {
resolve(param);
}
})
}
//Promise.reject
var p = Promise.reject('出错了');
// 等价于
var p = new Promise((resolve, reject) => reject('出错了'))
Promise.reject = function (reason) {
return new Promise((resolve, reject) => {
reject(reason);
});
}
//Promise.prototype.finally
Promise.prototype.finally = function(callback) {
this.then(value => {
return Promise.resolve(callback()).then(() => {
return value;
})
}, error => {
return Promise.resolve(callback()).then(() => {
throw error;
})
})
}
//Promise.all 成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。
//传入参数为一个空的可迭代对象,则`直接进行resolve`
//如果参数中`有一个`promise失败,那么Promise.all返回的promise对象失败
//在任何情况下,Promise.all 返回的 promise 的完成状态的结果都是一个`数组`
Promise.all = function(promises) {
return new Promise((resolve, reject) => {
let result = [];
let len = promises.length;
if(len === 0) {
resolve(result);
return;
}
const handleData = (data, index) => {
result[index] = data;
// 最后一个 promise 执行完
if(index == len - 1) resolve(result);
}
for(let i = 0; i < len; i++) {
// 为什么不直接 promise[i].then, 因为promise[i]可能不是一个promise
Promise.resolve(promise[i]).then(data => {
handleData(data, i);
}).catch(err => {
reject(err);
})
}
})
}
//Promise.race
Promise.race = function(promises) {
return new Promise((resolve, reject) => {
let len = promises.length;
if(len === 0) return;
for(let i = 0; i < len; i++) {
Promise.resolve(promise[i]).then(data => {
resolve(data);
return;
}).catch(err => {
reject(err);
return;
})
}
})
}
promise.all接受是一个数组,里面可以是常量和promise,promise.all一个报错,其他还会执行
Promise.allSettled():接受一组Promise实例作为参数,包装成一个新的Promise实例。只有等到所有这些参数实例都返回结果,不管是fulfilled还是rejected,包装实例才会结束。返回值allSettledPromise,状态只可能变成fulfilled。它的监听函数接收到的参数是数组results(含fulfilled的结果 orrejected的结果)。
Promise.allSettled = Promise.allSettled || function(promises) {
return new Promise(function(resolve, reject) {
if (!Array.isArray(promises)) {
return reject(
new TypeError("arguments must be an array")
);
}
var resolvedCounter = 0;
var promiseNum = promises.length;
var resolvedValues = new Array(promiseNum);
for (var i = 0; i < promiseNum; i++) {
(function(i) {
Promise.resolve(promises[i]).then(
function(value) {
resolvedCounter++;
resolvedValues[i] = value;
if (resolvedCounter == promiseNum) {
return resolve(resolvedValues);
}
},
function(reason) {
resolvedCounter++;
resolvedValues[i] = reason;
if (resolvedCounter == promiseNum) {
return reject(reason);
}
}
);
})(i);
}
});
};
Promise.any():接受一组Promise实例作为参数,包装成一个新的Promise实例。只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态,参数为成员错误结果数组。
async / await
Promise 的语法糖,专门解决回调地狱,async 函数返回一个 Promise 对象。async 函数内部 return 语句返回的值,会成为 then 方法回调函数的参数。
async function f() {
return 'hello world';
}
f().then(v => console.log(v)) // "hello world"
// 同时触发写法
let [foo, bar] = await Promise.all([getFoo(), getBar()]);