JS异步编程
基础内容
setTimeout 与 setInterval
定时回调进行中断执行
let x = 3;
setTimeout(() => {
x = x + 3;
console.log(x);
}, 1000);
循环中断 每隔1000ms就会执行一次回调函数
setInterval(() => {
x = x + 3;
console.log(x);
}, 1000);
异步解决方案
老的异步方案 利用setTimeout解决
function double(value, callback) {
setTimeout(() => callback(value * 2), 1000);
}
double(3, (x) => console.log(`I was given ${x}`));
console.log("我先输出");
异常处理
function double(value, success, failure) {
setTimeout(() => {
try {
if (typeof value !== 'number') {
throw 'value type is not number';
}
success(value * 2); //成功回调
} catch (e) {
failure(e); //错误回调
}
}, 1000);
}
double('1', (res) => {
console.log("res", res);
}, (e) => {
console.error(e);
});
回调地狱
嵌套异步回调 一个异步任务等待另一个异步任务的返回值,一个异步代码中执行另一部分异步代码时,可能会出现回调地狱,简单的说就是我们原来的异步解决方案就是通过回调函数进行异步操作,就会出现回调里面还有回调这样的情况,如果任务较多可能会出现回调嵌套很多次,也就是我们说的回调地狱。
function double(value, success, failure) {
setTimeout(() => {
try {
if (typeof value !== 'number') {
throw 'value type is not number';
}
success(value * 2); //成功回调
} catch (e) {
failure(e); //错误回调
}
}, 1000);
}
const successCallback = (x) => {
double(x, (y) => console.log("y", y));
};
const failureCallback = (e) => console.error('e', e);
double(2, successCallback, failureCallback);
初识Promise
Promise是一种有三种状态的对象
- 待定 pending
- 兑现 fulfilled 也称解决resolved
- 拒绝 rejected
//Promise
let p = new Promise(() => {});
console.log(p);
setTimeout(console.log, 0, p);
//Promise是一个有状态的对象
//#通过执行函数控制Promise状态
let p1 = new Promise((resolve, reject) => {
resolve(); //把状态切换为兑现
});
console.log(p1);
//Promise {<fulfilled>: undefined}
let p2 = new Promise((resolve, reject) => {
reject(); //把状态切换为拒绝
});
console.log(p2);
//Promise {<rejected>: undefined}
当p被输出时,Promise状态还为待定状态
因为还没有执行resolve或reject
Promise状态一旦改变则不可逆,继续修改状态会静默失败
Promise的状态只能改变一次
new Promise(() => setTimeout(console.log, 0, 'executor'));
setTimeout(console.log, 0, 'promise initialized');
let p = new Promise((resolve, reject) => setTimeout(resolve, 1000));
setTimeout(console.log, 0, p);
Promise.resolve
创建的Promise对象默认状态为待定
但Promise并非一开始必须为待定状态
可以通过Promise.resolve()静态方法实例化一个resolve状态的Promise
let p1 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
let p2 = Promise.resolve();
console.log("p1", p1); //Promise {<pending>}
console.log("p2", p2); //Promise {<fulfilled>: undefined}
//Promise.resolve是一个静态方法
Promise.resolve(any) 可以把任何参数变为一个Promise
console.log(Promise.resolve(2));
//Promise {<fulfilled>: 2}
如果参数是一个Promise 则返回原来的Promise
let p3 = Promise.resolve(3);
console.log(p3 === Promise.resolve(p3));
//true
能够包装任何非Promise值,包括Error Object,
可以将其转换为resolved的Promise
console.log(Promise.resolve(new Error('error to promise')));
/*
Promise {< fulfilled >: Error: error to promise}
*/
Promise.reject
`
实例化一个拒绝状态的Promise并抛出一个异步错误
`
let p1 = new Promise((resolve, reject) => {
reject();
});
let p2 = Promise.reject();
console.log("p1", p1);
console.log("p2", p2);
`
二者是等价的,都是实例化了一个rejected状态的Promise
且二者都抛出了Uncaught Error
`
let p3 = Promise.reject(3);
console.log(p3); //Promise {<rejected>: 3}
p3.catch((e) => {
console.log("e", e); //e
})
`
e 就是reject传入的参数
本质还是创建了一个Promise 调用了reject(3)
`
`
如果reject的参数是一个Promise 并不像resolve
它会将其变为一个reject的理由即变为catch的参数
`
let p4 = Promise.resolve('成功');
p4.then((res) => {
console.log(res);
return Promise.resolve('连起来');
}).then((res) => {
console.log(res);
return Promise.reject('结束吧');
}).then((res) => {
console.log(res);
}).catch((e) => {
console.log(e);
}).finally(() => {
console.log("一切都结束了");
});
通俗理解Promise
Promise是一种对象、其有三种状态,resolve 表示解决 其传参可以被then传入的回调函数接收、reject 表示拒绝 其传参可以被 catch传入的回调函数接收。
利用Promise可以解决一定的回调地狱问题、使得代码维护性更高。
有趣的例子
const isPregnant = true;
const promise = new Promise((resolve, reject) => {
if (isPregnant) {
resolve('孩子他爹');
} else {
reject('老公');
}
});
promise.then(name => {
//resolve
console.log('男人成为了' + name);
}).catch(name => {
//reject
console.log('男人成为了' + name);
}).finally(() => {
console.log('男人和女人最终结婚了');
});
一个实际的例子
const imgPromise = (url) => {
return new Promise((resolve, reject) => {
const img = new Image();
img.src = url;
img.onload = () => {
resolve(img);
}
img.onerror = () => {
reject(new Error('图片加载出现错误'));
}
});
}
imgPromise('https:/cdn.jim-nielsen.com/ios/512/netflix-2018-11-01.png').then(img => {
document.body.appendChild(img);
}).catch(err => {
const p = document.createElement('p');
p.innerHTML = err;
document.body.appendChild(p);
});
//可见利用Promise可以有效的解决回调地狱问题
更新中 最后编辑(2022/2/20)…