JS是单线程的
-
1.JS是单线程的
- 所以JS中的代码都是串行的,前面没有执行完毕后面不能执行
-
2.JS分为同步代码和异步代码
- 除了"事件绑定的函数"和"回调函数"以外的都是同步代码
- 2.1程序运行会从上至下依次执行所有的同步代码
- 2.2在执行的过程中如果遇到异步代码会将异步代码放到事件循环中
- 2.3当所有同步代码都执行完毕后,JS会不断检测事件循环中的异步代码是否满足条件
- 2.4一旦满足条件就执行满足条件的异步代码
- 这也就是为什么有时输出的顺序跟编写代码的顺序不一致的原因
-
3.为什么JS是单线程的?
- javaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。
- 这决定了它只能是单线程,否则会带来很复杂的同步问题。
例如:
如果JS是多线程的,现在有一个线程要修改元素中的内容, 一个线程要删除该元素,这时浏览器应该以哪个线程为准?
promise基本概念
-
1.什么是promise?
- promise是ES6中新增的异步编程解决方案, 在代码中的表现是一个对象
示例需求: 从网络上加载3个资源,要求加载完资源1才能加载资源2, 加载完资源2才能加载资源3
前面任何一个资源加载失败, 后续资源都不加载
以前的解决方案(层层嵌套):
function request(fn) {
setTimeout(function () {
fn("拿到的数据");
}, 1000);
}
request(function (data) {
console.log(data, 1);
request(function (data) {
console.log(data, 2);
request(function (data) {
console.log(data, 3);
});
});
});
- 2.promise作用
- 企业开发中为了保存异步代码的执行顺序, 那么就会出现回调函数层层嵌套
- 如果回调函数嵌套的层数太多,就会导致代码的阅读性, 可维护性大大降低
- promise对象可以将异步操作以同步流程来表示, 避免了回调函数层层嵌套(回调地狱)
不用层层嵌套函数,可以这样解决:
function request() {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("拿到的数据");
}, 1000);
});
}
request().then(function (data) {
console.log(data, 1);
return request();
}).then(function (data) {
console.log(data, 2);
return request();
}).then(function (data) {
console.log(data, 3);
});
promise基本使用
-
1.什么是Promise?
- Promise是ES6中新增的一个对象,通过Promise就可以实现 用同步的流程来表示异步的操作
- 通过Promise就可以避免回调函数层层嵌套(回调地狱)问题
-
2.如何创建Promise对象?
- 格式:new Promise(function(resolve, reject){});
- promise对象不是异步的,只要创建promise对象就会立即执行存放的代码
-
3.Promise是如何实现通过同步的流程来表示异步的操作的?
- promise对象是通过状态的改变来实现的, 只要状态发生改变就会自动触发对应的函数
-
4.Promise对象三种状态
- pending:默认状态,只要没有告诉promise任务是成功还是失败就是pending状态
- fulfilled(resolved):只要调用resolve函数, 状态就会变为fulfilled, 表示操作成功
- rejected:只要调用rejected函数,状态就会变为rejected, 表示操作失败
注意点:
状态一旦改变既不可逆,既从pending变为fulfilled, 那么永远都是fulfilled
既从pending变为rejected,那么永远都是rejected
- 5.监听Promise状态改变
- 我们还可以通过函数来监听状态的变化
- resolved --> then()
- rejected --> catch()
- 我们还可以通过函数来监听状态的变化
then方法
- then方法
- then方法接收两个参数,第一个参数是状态切换为成功时的回调,第二个参数是状态切换为失败时的回调
let promise = new Promise(function (resolve, reject) {
// resolve(); // 将状态修改为成功
reject(); // 将状态修改为失败
});
promise.then(function () {
console.log("成功");
}, function () {
console.log("失败");
});
- 1.then方法
- 在修改promise状态时,可以传递参数给then方法中的回调函数
// resolve = success, reject = error;
let promise = new Promise(function (resolve, reject) {
// resolve("111"); // success("111");
reject("aaa"); // error("aaa");
});
/*promise.then(function (data) {
console.log("成功", data);
}, function (data) {
console.log("失败", data);
}); */
function success(data) {
console.log(data);
}
function error(data) {
console.log(data);
}
promise.then(success, error); // aaa
- 2.then方法
- 同一个promise对象可以多次调用then方法,当该promise对象的状态改变时所有then方法都会被执行
let promise = new Promise(function (resolve, reject) {
// resolve();
reject();
});
promise.then(function () {
console.log("成功1");
}, function () {
console.log("失败1"); // 失败1
});
promise.then(function () {
console.log("成功2");
}, function () {
console.log("失败2"); // 失败2
});
- 3.then方法
- then方法每次执行完毕后会返回一个新的promise对象
let promise = new Promise(function (resolve, reject) {
resolve();
// reject();
});
let p2 = promise.then(function () {
console.log("成功1"); // 成功1
}, function () {
console.log("失败1");
});
console.log(p2); // 打印p2的promise对象
console.log(promise === p2); // false
- 4.then方法
- 可以通过上一个promise对象的then方法给下一个promise对象的then方法传递参数
let promise = new Promise(function (resolve, reject) {
// resolve("111");
reject("aaa");
});
let p2 = promise.then(function (data) {
console.log("成功1", data);
return "222";
}, function (data) {
console.log("失败1", data); // 失败1 aaa
return "bbb";
});
p2.then(function (data) {
console.log("成功2", data); // 成功2 bbb
}, function (data) {
console.log("失败2", data);
});
注意点:
无论是在上一个promise对象成功的回调还是失败的回调传递的参数,
都会传递给下一个promise对象成功的回调
- 5.then方法
- 如果then方法返回的是一个Promise对象,那么会将返回的Promise对象的执行结果中的值传递给下一个then方法
let promise = new Promise(function (resolve, reject) {
resolve("111");
// reject("aaa");
});
let ppp = new Promise(function (resolve, reject) {
// resolve("222");
reject("bbb");
});
let p2 = promise.then(function (data) {
console.log("成功1", data); // 成功1 111
return ppp;
}, function (data) {
console.log("失败1", data);
return "bbb";
});
p2.then(function (data) {
console.log("成功2", data);
}, function (data) {
console.log("失败2", data); // 失败2 bbb
});
catch方法
- 1.catch方法
- catch 其实是 then(undefined, () => {}) 的语法糖
- 只有then失败才会执行,不监听成功
- catch只有一个参数
let promise = new Promise(function (resolve, reject) {
// resolve(); // 将状态修改为成功,不输出
reject(); // 将状态修改为失败 才输出
});
promise.catch(function () {
console.log("abc"); // abc
});
- 2.catch方法
- 注意点: 如果需要分开监听,也就是通过then监听成功通过catch监听失败,那么必须使用链式编程, 否则会报错
let promise = new Promise(function (resolve, reject) {
// resolve();
reject();
});
promise.then(function () {
console.log("成功");
}).catch(function () { // 监听失败
console.log("失败");
});
/* 这么写会报错,没用链式编程
promise.then(function () {
console.log("成功");
});
promise.catch(function () {
console.log("失败");
});
*/
- 3.catch方法
- 不使用链式编程报错的原因是
- 1.如果promise的状态是失败,但是没有对应失败的监听就会报错
- 2.then方法会返回一个新的promise,新的promise会继承原有promise的状态(原有的是成功状态,那继承的就是成功状态,反之亦然)
- 3.如果新的promise状态是失败,但是没有对应失败的监听也会报错
- 不使用链式编程报错的原因是
let promise = new Promise(function (resolve, reject) {
// resolve(); // 将状态修改为成功
reject(); // 将状态修改为失败
});
let p2 = promise.then(function () {
console.log("成功"); // 执行完返回的是一个新的promise,并且状态是继承的失败状态
});
console.log(p2);
promise.catch(function () {
console.log("失败1");
});
p2.catch(function () { // 监听新的promise失败状态
console.log("失败2");
});
catch方法特点、与then使用的区别
- 1.catch方法(同then)
- 在修改promise状态时,可以传递参数给catch方法中的回到函数
let promise = new Promise(function (resolve, reject) {
reject("111");
});
promise.catch(function (data) {
console.log(data); // 111
});
- 2.catch方法(同then)
- 同一个promise对象可以多次调用catch方法,当该promise对象的状态改变时所有catch方法都会被执行
let promise = new Promise(function (resolve, reject) {
reject();
});
promise.catch(function () {
console.log("失败1"); // 失败1
});
promise.catch(function () {
console.log("失败2"); // 失败2
});
promise.catch(function () {
console.log("失败3"); // 失败3
});
- 3.catch方法(同then)
- catch方法每次执行完毕后会返回一个新的promise对象
let promise = new Promise(function (resolve, reject) {
reject();
});
let p2 = promise.catch(function () {
console.log("失败1"); //失败1
});
console.log(p2); // 打印p2的promise对象
console.log(promise === p2); // false
- 4.catch方法(同then)
- 上一个promise对象也可以给下一个promise成功的传递参数
let promise = new Promise(function (resolve, reject) {
reject();
});
let p2 = promise.catch(function () {
console.log("失败1"); // 失败1
return "it666";
});
p2.then(function (data) {
console.log("成功2", data); // 成功2 it666
}, function (data) {
console.log("失败2", data);
});
注意点:
无论是在上一个promise对象成功的回调还是失败的回调传递的参数,都会传递给下一个promise对象成功的回调
- 5.catch方法(同then)
- catch方法如果返回的是一个Promise对象,那么会将返回的Promise对象的,执行结果中的值传递给下一个catch方法
let promise = new Promise(function (resolve, reject) {
reject();
});
let ppp = new Promise(function (resolve, reject) {
// resolve("1111");
reject("abcd");
});
let p2 = promise.catch(function () {
console.log("失败1"); // 失败1
return ppp;
});
p2.then(function (data) {
console.log("成功2", data);
}, function (data) {
console.log("失败2", data); // 失败2 abcd
});
- 6.catch方法(==不同于then的地方==)
- 和then方法第二个参数的区别在于,catch方法可以捕获上一个promise对象then方法中的异常
let promise = new Promise(function (resolve, reject) {
resolve();
// reject(); // 输出: 失败 undefined
});
/*
promise.then(function () {
console.log("成功"); // 成功
xxx // 报错
}, function () {
console.log("失败");
});
*/
应这么写:
promise.then(function () {
console.log("成功"); // 成功
xxx
}).catch(function (e) {
console.log("失败", e); // 失败 并输出报错内容
});
异常处理
-
1.JS中的异常
- 简单粗暴就是有错误出现
- 由于JS是单线程的, 编写的代码都是串行的,所以一旦前面代码出现错误,程序就会被中断, 后续代码就不会被执行
-
2.JS中的异常处理
- 2.1自身编写代码问题, --> 手动修复BUG
- 2.2外界原因问题, --> try{}catch{}
对于一些可预见的异常,我们可以使用try{}catch{}来处理
-
3.JS中如何进行异常处理
- 利用try{}catch{}来处理异常可以保证程序不被中断, 也可以记录错误原因以便于后续优化迭代更新
- 格式:try {可能遇到的意外的代码}catch(e) {捕获错误的代码块}
console.log("1"); // 1
say(); // 报错,执行暂停,不会执行之后代码
console.log("2");
想发生错误代码也要执行完代码的话,用try&catch:
console.log("1"); // 1
try {
say();
}catch (e) {
console.log(e); // 输出try里的错误地方,然后继续执行下面代码
}
console.log("2"); // 2
手撕Promise上
- 1.Promise特点
- 1.1创建时必须传入一个函数, 否则会报错
- 1.2会给传入的函数设置两个回调函数
- 1.3刚创建的Promise对象状态是pending
- 1.4状态一旦发生改变就不可再次改变
- 1.5可以通过then来监听状态的改变
- 1.5.1如果添加监听时状态已经改变,立即执行监听的回调
- 1.5.2如果添加监听时状态还未改变,那么状态改变时候再执行监听回到
- 1.5.3同一个Promise对象可以添加多个then监听,状态改变时所有的监听按照添加顺序执行
<script>
// 定义常量保存对象的状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class MyPromise{
constructor(handle){
// 0.初始化默认的状态
this.status = PENDING;
// 定义变量保存传入的参数
this.value = undefined;
this.reason = undefined;
// 定义变量保存监听的函数
// this.onResolvedCallback = null;
// this.onRejectedCallback = null;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
// 1.判断是否传入了一个函数, 如果没有传入就抛出一个异常
if(!this._isFunction(handle)){
throw new Error("请传入一个函数");
}
// 2.给传入的函数传递形参(传递两个函数)
// handle();
handle(this._resolve.bind(this), this._reject.bind(this));
}
then(onResolved, onRejected){
// 1.判断有没有传入成功的回调
if(this._isFunction(onResolved)){
// 2.判断当前的状态是否是成功状态
if(this.status === FULFILLED){
onResolved(this.value);
}
}
// 1.判断有没有传入失败的回调
if(this._isFunction(onRejected)){
// 2.判断当前的状态是否是失败状态
if(this.status === REJECTED){
onRejected(this.reason);
}
}
// 2.判断当前的状态是否是默认状态
if(this.status === PENDING){
if(this._isFunction(onResolved)){
// this.onResolvedCallback = onResolved;
this.onResolvedCallbacks.push(onResolved);
}
if(this._isFunction(onRejected)){
// this.onRejectedCallback = onRejected;
this.onRejectedCallbacks.push(onRejected);
}
}
}
_resolve(value){
// console.log("_resolve");
// 这里是为了防止重复修改
if(this.status === PENDING){
this.status = FULFILLED;
this.value = value;
// this.onResolvedCallback(this.value);
this.onResolvedCallbacks.forEach(fn => fn(this.value));
}
}
_reject(reason){
// console.log("_reject");
if(this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
// this.onRejectedCallback(this.reason);
this.onRejectedCallbacks.forEach(fn => fn(this.reason));
}
}
_isFunction(fn){
return typeof fn === "function";
}
}
</script>
<script>
// 测试:
let promise = new MyPromise(function (resolve, reject) {
// console.log(resolve);
// console.log(reject);
// resolve("111");
// reject("aaa");
setTimeout(function () {
// resolve("111");
reject("aaa");
}, 2000);
});
promise.then(function (data) {
console.log("成功1", data);
}, function (data) {
console.log("失败1", data);
});
promise.then(function (data) {
console.log("成功2", data);
}, function (data) {
console.log("失败2", data);
});
promise.then(function (data) {
console.log("成功3", data);
}, function (data) {
console.log("失败3", data);
});
console.log(promise);
</script>
手撕Promise中
- 1.Promise特点
- 1.1then方法每次执行完毕都会返回一个新的Promise对象
- 1.2上一个Promise对象的then可以给下一个Promise的then传递数据
- 1.2.1无论上一个是在成功的回调还是失败的回调传递的参数都会传递给下一个成功的回调
- 1.2.2如果上一个传递的是Promise对象,那么传给下一个的成功还是失败由传递的Promise状态决定
升级版:
<script>
// 定义常量保存对象的状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class MyPromise{
constructor(handle){
// 0.初始化默认的状态
this.status = PENDING;
// 定义变量保存传入的参数
this.value = undefined;
this.reason = undefined;
// 定义变量保存监听的函数
// this.onResolvedCallback = null;
// this.onRejectedCallback = null;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
// 1.判断是否传入了一个函数, 如果没有传入就抛出一个异常
if(!this._isFunction(handle)){
throw new Error("请传入一个函数");
}
// 2.给传入的函数传递形参(传递两个函数)
// handle();
handle(this._resolve.bind(this), this._reject.bind(this));
}
then(onResolved, onRejected){
return new MyPromise((nextResolve, nextReject) => {
// 1.判断有没有传入成功的回调
if(this._isFunction(onResolved)){
// 2.判断当前的状态是否是成功状态
if(this.status === FULFILLED){
// 拿到上一个promise成功回调执行的结果
let result = onResolved(this.value);
// console.log("result", result);
// 判断执行的结果是否是一个promise对象
if(result instanceof MyPromise){
result.then(nextResolve, nextReject);
}else{
// 将上一个promise成功回调执行的结果传递给下一个promise成功的回调
nextResolve(result);
}
}
}
// 1.判断有没有传入失败的回调
if(this._isFunction(onRejected)){
// 2.判断当前的状态是否是失败状态
if(this.status === REJECTED){
let result = onRejected(this.reason);
if(result instanceof MyPromise){
result.then(nextResolve, nextReject);
}else {
nextResolve(result);
}
}
}
// 2.判断当前的状态是否是默认状态
if(this.status === PENDING){
if(this._isFunction(onResolved)){
// this.onResolvedCallback = onResolved;
this.onResolvedCallbacks.push(() => {
let result = onResolved(this.value);
if(result instanceof MyPromise){
result.then(nextResolve, nextReject);
}else {
nextResolve(result);
}
});
}
if(this._isFunction(onRejected)){
// this.onRejectedCallback = onRejected;
this.onRejectedCallbacks.push(() => {
let result = onRejected(this.reason);
if(result instanceof MyPromise){
result.then(nextResolve, nextReject);
}else {
nextResolve(result);
}
});
}
}
});
}
_resolve(value){
// console.log("_resolve");
// 这里是为了防止重复修改
if(this.status === PENDING){
this.status = FULFILLED;
this.value = value;
// this.onResolvedCallback(this.value);
this.onResolvedCallbacks.forEach(fn => fn(this.value));
}
}
_reject(reason){
// console.log("_reject");
if(this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
// this.onRejectedCallback(this.reason);
this.onRejectedCallbacks.forEach(fn => fn(this.reason));
}
}
_isFunction(fn){
return typeof fn === "function";
}
}
</script>
<script>
// 测试:
let promise = new MyPromise(function (resolve,reject) {
// resolve("111");
// reject("aaa");
setTimeout(function () {
// resolve("111");
reject("aaa");
}, 2000);
});
let ppp = new MyPromise(function (resolve, reject) {
// resolve("222");
reject("bbb");
});
let p2 = promise.then(function (data) {
console.log("成功1", data);
// return "222";
return ppp;
}, function (data) {
console.log("失败1", data);
// return "bbb";
return ppp;
});
p2.then(function (data) {
console.log("成功2", data);
}, function (data) {
console.log("失败2", data);
});
// console.log(p2);
// console.log(promise === p2);
</script>
手撕Promise下
- 1.Promise特点
- 1.1then方法返回的Promise对象的状态和前一个Promise的状态默认相同
- 1.2后一个Promise对象的then可以捕获前一个Promise then的异常
- 1.3catch方法就是then方法的语法糖 then(undefined, function(){});
终极版:
<script>
// 定义常量保存对象的状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class MyPromise{
constructor(handle){
// 0.初始化默认的状态
this.status = PENDING;
// 定义变量保存传入的参数
this.value = undefined;
this.reason = undefined;
// 定义变量保存监听的函数
// this.onResolvedCallback = null;
// this.onRejectedCallback = null;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
// 1.判断是否传入了一个函数, 如果没有传入就抛出一个异常
if(!this._isFunction(handle)){
throw new Error("请传入一个函数");
}
// 2.给传入的函数传递形参(传递两个函数)
handle(this._resolve.bind(this), this._reject.bind(this));
}
then(onResolved, onRejected){
return new MyPromise((nextResolve, nextReject) => {
// 1.判断有没有传入成功的回调
if(this._isFunction(onResolved)){
// 2.判断当前的状态是否是成功状态
if(this.status === FULFILLED){
try {
// 拿到上一个promise成功回调执行的结果
let result = onResolved(this.value);
// console.log("result", result);
// 判断执行的结果是否是一个promise对象
if(result instanceof MyPromise){
result.then(nextResolve, nextReject);
}else{
// 将上一个promise成功回调执行的结果传递给下一个promise成功的回调
nextResolve(result);
}
}catch (e) {
nextReject(e);
}
}
}
// 1.判断有没有传入失败的回调
// if(this._isFunction(onRejected)){
try {
// 2.判断当前的状态是否是失败状态
if(this.status === REJECTED){
let result = onRejected(this.reason);
if(result instanceof MyPromise){
result.then(nextResolve, nextReject);
}else if(result !== undefined){
nextResolve(result);
}else{
nextReject();
}
}
}catch (e) {
nextReject(e);
}
// }
// 2.判断当前的状态是否是默认状态
if(this.status === PENDING){
if(this._isFunction(onResolved)){
// this.onResolvedCallback = onResolved;
this.onResolvedCallbacks.push(() => {
try {
let result = onResolved(this.value);
if(result instanceof MyPromise){
result.then(nextResolve, nextReject);
}else{
nextResolve(result);
}
}catch (e) {
nextReject(e);
}
});
}
// if(this._isFunction(onRejected)){
// this.onRejectedCallback = onRejected;
this.onRejectedCallbacks.push(() => {
try {
let result = onRejected(this.reason);
if(result instanceof MyPromise){
result.then(nextResolve, nextReject);
}else if(result !== undefined){
nextResolve(result);
}else{
nextReject();
}
}catch (e) {
nextReject(e);
}
});
// }
}
});
}
catch(onRejected){
return this.then(undefined, onRejected);
}
_resolve(value){
// 这里是为了防止重复修改
if(this.status === PENDING){
this.status = FULFILLED;
this.value = value;
// this.onResolvedCallback(this.value);
this.onResolvedCallbacks.forEach(fn => fn(this.value));
}
}
_reject(reason){
if(this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
// this.onRejectedCallback(this.reason);
this.onRejectedCallbacks.forEach(fn => fn(this.reason));
}
}
_isFunction(fn){
return typeof fn === "function";
}
}
</script>
<script>
// 测试:
let promise = new MyPromise(function (resolve, reject) {
// resolve();
// reject();
setTimeout(function () {
// resolve();
reject();
}, 5000);
});
let p2 = promise.then(function () {
console.log("成功");
});
p2.catch(function () {
console.log("失败");
});
// console.log(promise, p2);
/*
promise.then(function () {
console.log("成功");
}).catch(function () {
console.log("失败");
});
*/
</script>