https://juejin.im/post/5b55c28ee51d45195a7139d6
/*Promise 的简单实现*/
class MyPromise {
constructor(fn) {
this.resolvedCallbacks = [];
this.rejectedCallbacks = [];
this.state = "PADDING";
this.value = "";
fn(this.resolve.bind(this), this.reject.bind(this));
}
resolve(value) {
if (this.state === "PADDING") {
this.state = "RESOLVED";
this.value = value;
this.resolvedCallbacks.forEach(cb => cb());
}
}
reject(value) {
if (this.state === "PADDING") {
this.state = "REJECTED";
this.value = value;
this.rejectedCallbacks.forEach(cb => cb());
}
}
then(resolve = function() {}, reject = function() {}) {
if (this.state === "PADDING") {
this.resolvedCallbacks.push(resolve);
this.rejectedCallbacks.push(reject);
}
if (this.state === "RESOLVED") {
resolve(this.value);
}
if (this.state === "REJECTED") {
reject(this.value);
}
}
}
扩展 Promise.prototype.then和Promise.prototype.catch方法返回promise对象,所以它可以被链式调用。但此时返回的是以函数返回值生成的新的Promise实例,不是原来的那个Promise实例。
1.Promise对象的错误具有冒泡性质,会一直向后传递,直到被捕获为止。也就是说错误一定会被catch语句捕获。
,既然我then()方法第二个参数可以用来抛出错误,干嘛还要用这个catch()方法。
其实还是有区别的,在链式操作里,任何promise抛出的同步或异步错误都可以被then()方法捕获,而reject则处理当前promise的错误。因此,建议不要在then方法里面定义 reject 状态的回调函数(即then的第二个参数),总是使用catch方法,这样也更接近同步的写法(try/catch)。
使用.catch()捕捉错误
// ------------ 不好的写法 -------------
promise.then(function(data) {
// success
}, function(err) { //仅处理promise运行时发生的错误。无法处理回调中的错误
// error
});
// ------------ 好的写法 ------------
promise.then(res => {
// success
}).catch(err => { // 处理 promise 和 前一个回调函数运行时发生的错误
// error
});
因为promise抛出的错误不会传递到外层,当使用第一种写法时,成功回调的错误无法处理,因此建议使用catch方法。
// ------------ 好的写法 ------------
new Promise((resolve) => {
console.log("Step 1");
setTimeout(() => {
resolve("100");
}, 1000);
})
.then((value) => {
// value => 100
//返回一个promise对象
return new Promise((resolve) => {
console.log("Step 1-1");
setTimeout(() => {
resolve("110");
}, 1000);
});
})
.then((value) => {
// value => 110
console.log("Step 1-2");
return value;
})
.then((value) => {
// value => 110
console.log("Step 1-3");
return value;
})
.then((value) => {
console.log(value); // value = 110
console.log("Step 2");
});
//then方法中,永远return或throw
//------------ 不好的写法 ------------------
promise.then(function () {
getUserInfo(userId);
}).then(function () {
// 在这里可能希望在这个回调中使用用户信息,但你可能会发现它根本不存在
});
如果要使用链式then,必须返回一个promise对象。
//改造
return new Promise((resolve) => {
console.log("Step 1-1");
getUserInfo(userId);
});
asycn/await与promise简单比较
不使用async/await
function takelongtime() {
return new Promise(resolve =>{
setTimeout(()=> resolve('hhhhhh'),1000)})
}
takelongtime().then(value => console.log('kkkkkk',value)
使用async/await
function takelongtime() {
return new Promise(resolve =>{
setTimeout(()=> resolve('hhhhhh'),1000)})
}
async function test() {
const value = await takelongtime();
console.log(value)
}
test()
结论
1、async/await的优势在于处理then链
Promise通过then链来解决多层回调问题,但如果需要同时处理由多个Promise组成的then链,就可以用async/await来进一步优化
2、async/await优点:代码更加简洁。
场景:
假设一个场景,分多个步骤完成,每个步骤都是异步的,而且依赖于上一个步骤的结果
function takeLongTime(n) {
return new Promise(resolve => {
setTimeout(() => resolve(n + 200), n);
});
}
function step1(n) {
console.log(`step1 with ${n}`);
return takeLongTime(n);
}
function step2(n) {
console.log(`step2 with ${n}`);
return takeLongTime(n);
}
function step3(n) {
console.log(`step3 with ${n}`);
return takeLongTime(n);
}
用Promise方法来实现这几个步骤的处理:
function doIt() {
console.time("doIt");
const time1 = 300;
step1(time1)
.then(time2 => step2(time2))
.then(time3 => step3(time3))
.then(result => {
console.log(`result is ${result}`);
console.timeEnd("doIt");
});
}
doIt();
// step1 with 300
// step2 with 500
// step3 with 700
// result is 900
// doIt: 1580.487ms
用async/await来实现
async function doIt() {
console.time("doIt");
const time1 = 300;
const time2 = await step1(time1);
const time3 = await step2(time2);
const result = await step3(time3);
console.log(`result is ${result}`);
console.timeEnd("doIt");
}
doIt();
后续步骤需要多个返回值:
function takeLongTime(n) {
return new Promise(resolve => {
setTimeout(() => resolve(n + 200), n);
});
}
function step1(n) {
console.log(`step1 with ${n}`);
return takeLongTime(n);
}
function step2(m, n) {
console.log(`step2 with ${m} and ${n}`);
return takeLongTime(m + n);
}
function step3(k, m, n) {
console.log(`step3 with ${k}, ${m} and ${n}`);
return takeLongTime(k + m + n);
}
用promise处理,就会发现处理返回值会比较麻烦
function doIt() {
console.time("doIt");
const time1 = 300;
step1(time1)
.then(time2 => {
return step2(time1, time2)
.then(time3 => [time1, time2, time3]);
})
.then(times => {
const [time1, time2, time3] = times;
return step3(time1, time2, time3);
})
.then(result => {
console.log(`result is ${result}`);
console.timeEnd("doIt");
});
}
doIt();
用async/await处理:
async function doIt() {
console.time("doIt");
const time1 = 300;
const time2 = await step1(time1);
const time3 = await step2(time1, time2);
const result = await step3(time1, time2, time3);
console.log(`result is ${result}`);
console.timeEnd("doIt");
}
doIt();
// step1 with 300
// step2 with 800 = 300 + 500
// step3 with 1800 = 300 + 500 + 1000
// result is 2000
// doIt: 2907.387ms
结论2:
2、async/await的优点:解决promise传递参数太麻烦的问题。
3、async/await使用try...catch处理rejected状态
async function myFunction() {
try {
await somethingThatReturnsAPromise();
} catch (err) {
console.log(err);
}
}
// 另一种写法
async function myFunction() {
await somethingThatReturnsAPromise().catch(function (err){
console.log(err);
});
}
异步加载图片
用promise实现异步加载图片的例子
function loadImageAsync(url) {
return new Promise((resolve, reject) => {
const image = new Image();
image.onload = () => {
resolve(image);
};
image.onerror = () => {
reject(new Error('Could not load image at ' + url));
};
image.src = url;
});
}
const loadImage = loadImageAsync(url);
[参考链接]https://juejin.im/post/5d7de1cc6fb9a06af471f1a7
[参考链接]https://juejin.im/post/5d42970bf265da03c34bdb95