Promise三种状态
- pending【等待中】
- resolved【完成了】
- rejected【拒绝了】
Promise是JS对于异步方法的实现,解决了传统方法的地狱回调,传统方法的地狱回调会导致代码层层嵌套非常混乱
基本用法
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。
resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。
通过then方法可以实现Promise链,在then中第一个回调方法是resolve,第二个回调方法是reject,在resolve方法中再返回Promise,则可以继续在外层通过then继续回调
promise.then(function(value) {
// success
}, function(error) {
// failure
});
reject和catch的区别
- 在then回调中,resolve回调方法中报错的话,reject是无法捕获的,reject是决定状态的失败回调,在进入到resolve方法后,就与reject无关了
- 如果某个then报错了,会一直保持reject状态,直到进入catch
- 在异步回调中报错,不会被catch到
- promise状态变化为resolve或者reject后,就不会再改变了,所以在resolve或者reject后抛出错误,是不会触发到catch的
const test = new Promise((resolve, reject) => {
// throw "error"; // 可以捕获 输出 error
// resolve(666);
// throw "error"; // 不能捕获
setTimeout(() => {
throw "error"; // 不能捕获
}, 0);
});
test
.then((data) => {
console.log("data1", data);
// throw "error"; // 可以捕获,先输出666,再输出error
return Promise.resolve(777);
})
.then((data) => {
console.log("data2", data);
})
.catch((err) => {
console.log("err", err);
});
Promise.resolve
有时需要将现有对象转为 Promise 对象,Promise.resolve方法就起到这个作用。
Promise.resolve等价于下面的写法
Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))
1)参数是一个 Promise 实例
如果参数是 Promise 实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。
2)参数是一个thenable对象
thenable对象指的是具有then方法的对象,Promise.resolve方法会将这个对象转为 Promise 对象,然后就立即执行thenable对象的then方法。
let thenable = {
then: function(resolve, reject) {
resolve(42);
}
};
let p1 = Promise.resolve(thenable);
p1.then(function(value) {
console.log(value); // 42
});
3)参数不是具有then方法的对象,或根本就不是对象。 如果参数是一个原始值,或者是一个不具有then方法的对象,则Promise.resolve方法返回一个新的 Promise 对象,状态为resolved。
const p = Promise.resolve('Hello');
p.then(function (s){
console.log(s)
});
// Hello
4)不带有任何参数
Promise.resolve方法允许调用时不带参数,直接返回一个resolved状态的 Promise 对象。
所以,如果希望得到一个 Promise 对象,比较方便的方法就是直接调用Promise.resolve方法。
const p = Promise.resolve();
p.then(function () {
// ...
});
Promise.reject
Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected。
const p = Promise.reject('出错了');
// 等同于
const p = new Promise((resolve, reject) => reject('出错了'))
p.then(null, function (s) {
console.log(s)
});
// 出错了
上面代码生成一个 Promise 对象的实例p,状态为rejected,回调函数会立即执行。
注意,Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。这一点与Promise.resolve方法不一致。
const thenable = {
then(resolve, reject) {
reject('出错了');
}
};
Promise.reject(thenable)
.catch(e => {
console.log(e === thenable)
})
// true
上面代码中,Promise.reject方法的参数是一个thenable对象,执行以后,后面catch方法的参数不是reject抛出的“出错了”这个字符串,而是thenable对象。
其他常用API
Promise.all与Promise.allSettled
const test = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(666);
}, 0);
});
const test2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(777);
}, 0);
});
const test3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(888);
}, 0);
});
Promise.allSettled([test, test2, test3]).then((res) => {
console.log(res);
// [{status:'fulfilled',value:666},{status:'rejected';,value:777},{status:'fulfilled',value:888}]
});
Promise.all([test, test2, test3]).then(
(res) => {
console.log("ok", res);
},
(err) => {
console.log("err", err);
// err 777
}
);
Promise.all(iterable) 方法返回一个 Promise 实例,此实例在 iterable 参数内所有的 promise 都“完成(resolved)”或参数中不包含 promise 时回调完成(resolve)
如果参数中promise有一个失败(rejected),此实例回调失败(reject),失败的原因是第一个失败 promise 的结果。
Promise.allSettled会返回所有结果的数组,无论成功失败,状态通过数组中对象的status属性体现
Promise.any(截止当前,该方法处于stage4阶段,会在明年进入正式语法)
只要有一个resolve了,则返回结果,如果一个都没有resolve,则返回失败
const pErr = new Promise((resolve, reject) => {
reject("总是失败");
});
const pSlow = new Promise((resolve, reject) => {
setTimeout(resolve, 500, "最终完成");
});
const pFast = new Promise((resolve, reject) => {
setTimeout(resolve, 100, "很快完成");
});
Promise.any([pErr, pSlow, pFast]).then((value) => {
console.log(value);
// pFast fulfils first
})
// 期望输出: "很快完成"
Promise.race
只要任意一个结果返回resolve或者reject,就立即返回结果
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'one');
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'two');
});
Promise.race([promise1, promise2]).then((value) => {
console.log(value);
// Both resolve, but promise2 is faster
});
// expected output: "two"
手写原理
手写实现Promise基础版
// 手写实现Promise
const PENDING = "pending";
const RESOLVED = "resolved";
const REJECTED = "rejected";
function MyPromise(fn) {
const that = this;
that.state = PENDING;
that.value = null;
that.resolvedCallbacks = [];
that.rejectedCallbacks = [];
function resolve(value) {
if (that.state === PENDING) {
that.state = RESOLVED;
that.value = value;
that.resolvedCallbacks.map((cb) => {
cb(value);
});
}
}
function reject(value) {
if (that.state === PENDING) {
that.state = REJECTED;
that.value = value;
that.rejectedCallbacks.map((cb) => {
cb(value);
});
}
}
try {
fn(resolve, reject);
} catch (e) {
reject(e);
}
}
MyPromise.prototype.then = function (onFulfilled, onRejected) {
const that = this;
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (v) => v;
onRejected =
typeof onRejected === "function"
? onRejected
: (r) => {
throw r;
};
if (that.state === PENDING) {
that.resolvedCallbacks.push(onFulfilled);
that.rejectedCallbacks.push(onRejected);
}
if (that.state === RESOLVED) {
onFulfilled(that.value);
}
if (that.state === REJECTED) {
onRejected(that.value);
}
};
手写实现Promise.all
Promise.all = function (promises) {
return new Promise((resolve, reject) => {
let index = 0;
const res = [];
if (!promises.length) {
resolve(res);
} else {
function processValue(i, data) {
res[i] = data;
if (++index === promises.length) {
resolve(res);
}
}
for (let i = 0; i < promises.length; i += 1) {
if (!promises[i] instanceof Promise) {
processValue(i, promises[i]);
} else {
promises[i].then(
(data) => {
processValue(i, data);
},
(err) => {
reject(err);
}
);
}
}
}
});
};
手写实现Promise.finally
Promise.finally = function (callback) {
return this.then(
(value) => {
return Promise.resolve(callback()).then(() => {
return value;
});
},
(err) => {
return Promise.resolve(callback()).then(() => {
throw err;
});
}
);
};
手写实现Promise.race
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i += 1) {
if (!promises[i] instanceof Promise) {
Promise.resolve(promises[i]).then(resolve, reject);
return;
} else {
promises[i].then(resolve, reject);
return;
}
}
});
};