回调函数
- 回调函数分为两种类型,分别为同步回调与异步回调;
- 同步回调:会立即执行,完全执行完了才结束,不会放入回调队列中;
- 异步回调:不会立即执行,会放入回调队列中 将来执行;
- 遍历回调属于同步回调,立即执行;
- 定时器中的回调属于异步回调,不会立即执行;
常见的内置错误
- Error:所有错误的父类型;
- ReferenceError:引用变量不存在;
- TypeError:数据类型不正确;
- RangeError:数据值不在其所允许的范围之内;
- SyntaxError:语法错误;
错误的处理
- 错误处理的方式有两种:捕获错误和抛出错误;
- 捕获错误:
try ... catch
;
- 抛出错误:
throw error
,错误由调用者进行处理;
Promise
- Promise是JS中进行异步编程的一种解决方案;
- 从语法上来说,Promise是一个构造函数;
- 从功能上来说,Promise对象用来封装一个异步操作并可以获取其结果;
Promise的状态
- 初始化状态为pending;
- pending变为resolved;
- pending变为reiected;
- 一个Promise对象,其状态只能改变一次,无论变为成功还是失败,都会有一个结果数据,成功的结果数据一般称为value,失败的结果数据一般称为reason;
- Promise执行的基本流程如下:
image.png
Promise的基本使用
- 首先创建Promise实例对象;
- 在执行器中执行异步任务;
- 获取异步任务的处理结果;
Promise的优点
- 首先Promise指定回调函数的方式更加灵活;
- 纯回调函数形式,指定回调函数必须在异步任务执行之前;
- Promise形式,指定回调函数在执行异步任务前后均可以,更加灵活;
- 其次Promise支持链式调用,可以解决回调地狱问题,终极解决方案为:async/await;
Promise常见API
image.png
-
Promise.resolve(value)
:返回值为一个新的promise,参数value值可以是promise,可以是非promise- 当value为非promise时,那么新promise的状态结果为resolve成功;
- 当value为promise时,那么新promise的状态结果为value的状态结果;
-
Promise.reject(value)
:返回值为一个新的promise,其状态结果为reject失败; -
Promise.all(promise数组)
:返回值为一个新的promise,其状态结果为:- 当promise数组中存在一个状态失败的,那么新promise的状态结果为失败;
- 当promise数组中都成功,那么新promise的状态结果为一个数组集合值;
-
Promise.race(promise数组)
:返回值为一个新的promise,其状态结果为:promise数组中先返回状态结果的promise的状态结果;
Promise的使用注意事项
- promise的状态改变分为三种情况:
- 执行成功resolve(value),pending --> resolve;
- 执行失败reject(reason),pending --> reject;
- 抛出异常 throw error,pending --> reject;
- 一个promise对象,可以指定多个状态回调,且多个状态回调都会执行;
- 如何控制
改变promise状态
和指定回调函数
的先后顺序?- 常规情况下:先指定回调函数,再改变promise状态,执行回调函数;
- promise.then()会返回一个新的promise对象,此promise的状态结果由什么决定?
- 由then()指定的回调函数执行的结果决定;
- then()指定的回调函数,没有返回值,则新的promise对象状态变成resolve,value值为undefined;
- then()指定的回调函数,返回非promise的任意值value,则新的promise对象状态变成resolve,会执行成功的回调,且获取value值;
- then()指定的回调函数,抛出异常,则新的promise对象状态变成reject,会执行失败的回调;
- then()指定的回调函数,返回另一个新的promise,则此promise的状态结果会成为新promise的状态结果;
- promise如何串联多个操作任务?
- promise.then()可返回一个新的promise;
- promise.then()的链式调用可串联多个同步/异步任务;
image.png
- promise的异常传透:
- 当使用promise的then链式调用时,可以再最后指定失败的回调;
- 前面任何操作出现了异常,都会传到最后失败的回调;
- . catch失败处理,上面没有失败的处理,就会执行. catch中的代码,
没有失败的处理
等价于reason => { throw reason }
,抛出了异常,然后一直往下传递异常,最终会执行. catch中的代码; - 如何中断promise链?
- 当使用promise的then链式调用时,在中间中断,不再调用后面的回调函数;
- 方案:在回调函数中返回一个pending状态的promise对象;
- 注意.catch()函数也会返回一个新的promise对象;
自定义Promise
- 函数对象,代码如下:
//自定义Promise函数模块
(function (window) {
const PENDING = 'pending';
const RESOLVED = 'resolved';
const REJECTED = 'rejected';
//Promise的构造函数
function Promise(excutor) {
const self = this;
//promise状态 初始化为pending
self.status = PENDING;
//promise异步操作的结果数据
self.data = undefined;
//promise的回调函数
self.callbacks = [];
function resolve(value) {
if (self.status !== PENDING) {
return;
}
//将状态改成resolved
self.status = RESOLVED;
self.data = value;
//若存在callback回调函数,则立即异步执行回调函数
if (self.callbacks.length > 0) {
setTimeout(() => {
self.callbacks.forEach(element => {
element.onResolved(value);
});
});
}
}
function reject(reason) {
if (self.status !== PENDING) {
return;
}
self.status = REJECTED;
self.data = reason;
if (self.callbacks.length > 0) {
setTimeout(() => {
self.callbacks.forEach(element => {
element.onRejected(reason);
});
});
}
}
try {
excutor(resolve, reject);
} catch (error) {
//捕获异常了 执行reject方法 状态成为rejected
reject(error);
}
}
//Promise原型上的函数方法
Promise.prototype.then = function (onResolved, onRejected) {
//当前promise对象
const self = this;
onResolved = typeof onResolved === 'function' ? onResolved : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
//返回一个新的promise对象
return new Promise((resolve, reject) => {
//处理函数
function handle(callback) {
//新promise对象的状态结果 由当前promise对象的状态结果决定
//1.当前promise结果为抛出异常,则新的promise结果为失败,值为异常error
//2.当前promise结果为非promise,则新的promise结果为成功,值为异常value
//3.当前promise结果为promise,则新的promise结果为promise的结果
try {
const result = callback(self.data);
if (result instanceof Promise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (error) {
reject(error);
}
}
if (this.status === RESOLVED) {
//立即异步执行 当前promise对象 成功的回调函数
setTimeout(() => {
handle(onResolved);
});
} else if (self.status === REJECTED) {
setTimeout(() => {
handle(onRejected);
});
} else {
//将成功和失败的回调函数保存到callbacks容器中
self.callbacks.push({
onResolved(value) {
handle(onResolved);
},
onRejected(reason) {
handle(onRejected);
}
});
}
});
if (self.status === PENDING) {
//保存回调方法 到一个对象中
self.callbacks.push({
onResolved,
onRejected
})
} else if (self.status === RESOLVED) {
setTimeout(() => {
resolve(self.data)
});
} else {
setTimeout(() => {
reject(self.data);
});
}
}
Promise.prototype.catch = function (onRejected) {
Promise.prototype.then(undefined, onRejected);
}
//Promise函数对象方法
Promise.resolve = function (value) {
//返回一个状态结果为 成功或失败的promise对象
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(resolve, reject);
} else {
resolve(value);
}
})
}
Promise.reject = function (reason) {
//返回一个状态结果为失败的promise对象
return new Promise((resolve, reject) => {
reject(reason);
})
}
Promise.all = function (promises) {
//保存所有成功的value的数组
const values = new Array(promises.length);
//记录成功promise的数量
let resloveCount = 0;
return new Promise((reslove, reject) => {
promises.forEach((p, index) => {
p.then(
value => {
resloveCount++;
values[index] = value;
if (resloveCount === promises.length) {
reslove(values);
}
},
reason => {
reject(reason);
}
)
});
});
}
Promise.race = function (promises) {
return new Promise((resove, reject) => {
promises.forEach((p, index) => {
p.then(
value => {
resove(value);
},
reason => {
reject(reason);
}
)
});
});
}
//向外暴露Promise的构造函数
window.Promise = Promise;
})(window)
- 类Class对象,代码如下:
//自定义Promise函数模块
(function (window) {
const PENDING = 'pending';
const RESOLVED = 'resolved';
const REJECTED = 'rejected';
class Promise {
constructor(excutor) {
//Promise的构造函数
const self = this;
//promise状态 初始化为pending
self.status = PENDING;
//promise异步操作的结果数据
self.data = undefined;
//promise的回调函数
self.callbacks = [];
function resolve(value) {
if (self.status !== PENDING) {
return;
}
//将状态改成resolved
self.status = RESOLVED;
self.data = value;
//若存在callback回调函数,则立即异步执行回调函数
if (self.callbacks.length > 0) {
setTimeout(() => {
self.callbacks.forEach(element => {
element.onResolved(value);
});
});
}
}
function reject(reason) {
if (self.status !== PENDING) {
return;
}
self.status = REJECTED;
self.data = reason;
if (self.callbacks.length > 0) {
setTimeout(() => {
self.callbacks.forEach(element => {
element.onRejected(reason);
});
});
}
}
try {
excutor(resolve, reject);
} catch (error) {
//捕获异常了 执行reject方法 状态成为rejected
reject(error);
}
}
//Promise原型上的函数方法
then(onResolved, onRejected) {
//当前promise对象
const self = this;
onResolved = typeof onResolved === 'function' ? onResolved : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
//返回一个新的promise对象
return new Promise((resolve, reject) => {
//处理函数
function handle(callback) {
//新promise对象的状态结果 由当前promise对象的状态结果决定
//1.当前promise结果为抛出异常,则新的promise结果为失败,值为异常error
//2.当前promise结果为非promise,则新的promise结果为成功,值为异常value
//3.当前promise结果为promise,则新的promise结果为promise的结果
try {
const result = callback(self.data);
if (result instanceof Promise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (error) {
reject(error);
}
}
if (this.status === RESOLVED) {
//立即异步执行 当前promise对象 成功的回调函数
setTimeout(() => {
handle(onResolved);
});
} else if (self.status === REJECTED) {
setTimeout(() => {
handle(onRejected);
});
} else {
//将成功和失败的回调函数保存到callbacks容器中
self.callbacks.push({
onResolved(value) {
handle(onResolved);
},
onRejected(reason) {
handle(onRejected);
}
});
}
});
if (self.status === PENDING) {
//保存回调方法 到一个对象中
self.callbacks.push({
onResolved,
onRejected
})
} else if (self.status === RESOLVED) {
setTimeout(() => {
resolve(self.data)
});
} else {
setTimeout(() => {
reject(self.data);
});
}
}
catch(onRejected) {
Promise.prototype.then(undefined, onRejected);
}
//Promise函数对象方法
static resolve(value) {
//返回一个状态结果为 成功或失败的promise对象
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(resolve, reject);
} else {
resolve(value);
}
})
}
static reject(reason) {
//返回一个状态结果为失败的promise对象
return new Promise((resolve, reject) => {
reject(reason);
})
}
static all(promises) {
//保存所有成功的value的数组
const values = new Array(promises.length);
//记录成功promise的数量
let resloveCount = 0;
return new Promise((reslove, reject) => {
promises.forEach((p, index) => {
p.then(
value => {
resloveCount++;
values[index] = value;
if (resloveCount === promises.length) {
reslove(values);
}
},
reason => {
reject(reason);
}
)
});
});
}
static race(promises) {
return new Promise((resove, reject) => {
promises.forEach((p, index) => {
p.then(
value => {
resove(value);
},
reason => {
reject(reason);
}
)
});
});
}
}
//向外暴露Promise的构造函数
window.Promise = Promise;
}
)(window)
async与await
-
async 函数
:函数的返回值是promise对象,promise对象的状态结果由async函数执行的返回值决定;
-
await 表达式
:一般情况下await右侧的表达式为promise对象,也可以是其他的值;‘- 若表达式是promise对象,await返回的是promise成功的值;
- 若表达式是其他值,直接将此值作为await的返回值;
- 注意事项:
- await必须写在async函数中,但async函数中可以没有await;
- 如果await的promise失败了,就会抛出异常,需要通过try...catch来捕获处理;
异步执行的宏队列与微队列
- 在JS中 存储 待执行回调函数的 队列 有两种特定的队列,分别为宏队列和微队列;
- 宏队列:用来保存待执行的宏任务回调函数,例如定时器回调,DOM事件回调,ajax回调;
- 微队列:用来保存待执行的微任务回调函数,例如Promise回调,MutationObserver回调;
- JS执行时会区分 这两个队列;
- JS引擎首先必须先执行完所有的初始化同步任务代码;
-
每次准备取出第一个宏任务执行前,都要将所有微任务一个一个取出来执行
;
image.png