1、回调函数定义
回调是一个在另一个函数完成执行后所执行的函数——故此得名“回调”。
2、为什么需要回调
JavaScript 是一种事件驱动的单线程语言。这意味着,在继续之前, JavaScript 不会等待响应,而是继续执行且同时监听事件。
举例:
function first(){
console.log(1);
}
function second(){
console.log(2);
}
first();
second();
//1
//2
如果再first中有计时器呢?function first(){
// 模拟代码延迟
setTimeout( function(){
console.log(1);
}, 500 );
}
function second(){
console.log(2);
}
first();
second();
//2
//1
//并不是 JavaScript 没有按照我们想要的顺序执行我们的函数,而是在继续执行 second() 之前, JavaScript 没有等待 first() 的响应。
1.回调函数字面意思:就是回调就是一个函数的调用过程。那么就从理解这个调用过程开始吧。函数a有一个参数,这个参数是个函数b,当函数a执行完以后执行函数b。那么这个过程就叫回调。
2.回调函数的意义:
异步:一般ajax请求都是异步的。请求发出去后,处理器会继续执行下面的代码。如果你想ajax请求完成后,做一些事情,显然,直接在下一行写代码是达不到目的。而作为回调函数传给ajax请求,可以控制请求在哪个阶段去调用回调函数,并且不用担心后面的代码执行到什么地方了。
3.回调函数的执行:就是异步的函数体执行成功或失败调用的传递进来的函数,调用的函数就是回调,为了不影响代码执行的效率,我们不会等待异步的代码执行,而是直接像下面执行,但是像请求,计时器,事件等操作我们在一些情况下必须拿到对应的数据或者返回值,这个时候就可以在异步函数里传入一个回调函数,也就是在异步操作执行结束之后会调用这个回调函数执行一段代码
3.回调的局限性
//普通函数
// 第一步,打开冰箱
function open(){
setTimeout(()=>{
console.log(‘打开冰箱’);
return ‘success’;
}, 1000)
}// 第二步,放牛进去
function settle(){
setTimeout(()=>{
console.log(‘放牛进去’);
return ‘success’;
}, 3000)
}// 第三步,关上冰箱
function close(){
setTimeout(()=>{
console.log(‘关上冰箱’);
return ‘success’;
}, 1000)
}function closeCow(){
open();
settle();
close()
}closeCow();
//“打开冰箱”
//“关上冰箱”?
//“放牛进去”?//回调函数实现
function closeCow() {
setTimeout(() => {
console.log(“打开冰箱”);
setTimeout(() => {
console.log(“放牛进去”);
setTimeout(() => {
console.log(“关闭冰箱”);
}, 1000);
}, 3000);
}, 1000);
}
如何解决回调嵌套?
1.保持你的代码简短(给函数取有意义的名字,见名知意,而非匿名函数,写成一大坨)
2.模块化(函数封装,打包,每个功能独立,可以单独的定义一个js文件Vue,react中通过import导入就是一种体现)
3.Promise/生成器/ES6等
4.Promise的特点
特点1
Promise有三种状态,分别是pending(进行中)、fulfilled(已成功)、rejected(已失败)。只有异步操作的结果可以决定当前是哪一种状态,任何其他操作都无法改变这个操作,Promise(承诺)这个名字也是由此而来,表示其他手段无法改变状态
特点2
如果状态发生了改变,就不会再改变而且任何时候都可以得到这个结果,Promise状态的改变只有两种情况一种是变为fulfilled另一种是变为rejected,改变后状态就凝固了不会再有任何改变,会一直保持这个结果,这是就成为resolved(已定形)。而且,如果改变已经发生你也可以对Promise添加回调函数获得结果,这与事件有根本的区别,事件如果不监听(dom.addEventListener),错过之后就无法再得到结果
特点3
无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
5.Promise的使用
基础语法
const promise = new Promise((resolve, reject) => {
resolve(‘fulfilled…’); // 状态由 pending --> fulfilled
});promise.then(res => {
console.log(res); // 只会调用 resolve
}, err => {
console.log(err); // 不会调用 rejected
})
// fulfilled
Promise
1.特性:
立即执行,自身是异步
let promise = new Promise(function(resolve, reject) {
console.log(‘Promise’);
resolve();
});promise.then(function() {
console.log(‘resolved.’);
});console.log(‘Hi!’);
// ?
// ?
// ?
上面代码中,Promise 新建后立即执行,所以首先输出的是Promise。然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以resolved最后输出。
2.特性
值穿透
Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log)
// 输出 ?
//Promise的then方法的参数期望是函数,传入非函数则会发生值穿透。
6.Promise API
比较简单,
建议查看MDN文档
7.手写Promise
核心点
1.状态的改变
2.值的改变
3.返回值
4.class的使用
基础版
// 构建
const PENDING = ‘pending’//进行中
const FULFILLED = ‘fulfilled’//已成功
const REJECTED = ‘rejected’//已失败class NewPromise {
//接受一个函数handle
constructor (handle) {
if (!isFunction(handle)) {
throw new Error(‘MyPromise must accept a function as a parameter’)
}
// 添加状态
this._status = PENDING
// 添加状态
this._value = undefined
// 添加成功回调函数队列
this._fulfilledQueues = []
// 添加失败回调函数队列
this._rejectedQueues = []
// 执行handle
try {
//执行回调函数,class是严格模式指向undefined,通过bind修改指向resove的指向
handle(this._resolve.bind(this), this._reject.bind(this))
//收集错误
} catch (err) {
this._reject(err)
}
}
}//then方法的对应状态的回调执行时机,值的改变
then (onFulfilled, onRejected) {
const { _value, _status } = this
switch (_status) {
// 当状态为pending时,将then方法回调函数加入执行队列等待执行
case PENDING:
this._fulfilledQueues.push(onFulfilled)
this._rejectedQueues.push(onRejected)
break
// 当状态已经改变时,立即执行对应的回调函数
case FULFILLED:
onFulfilled(_value)
break
case REJECTED:
onRejected(_value)
break
}
// 返回一个新的Promise对象
return new MyPromise((onFulfilledNext, onRejectedNext) => {
})
}//那返回的新的 Promise 对象什么时候改变状态?改变为哪种状态呢?
//then方法确认Promise状态
then (onFulfilled, onRejected) {
const { _value, _status } = this
// 返回一个新的Promise对象
return new MyPromise((onFulfilledNext, onRejectedNext) => {
// 封装一个成功时执行的函数
let fulfilled = value => {
try {
if (!isFunction(onFulfilled)) {
onFulfilledNext(value)
} else {
let res = onFulfilled(value);
if (res instanceof MyPromise) {
// 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调
res.then(onFulfilledNext, onRejectedNext)
} else {
//否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数
onFulfilledNext(res)
}
}
} catch (err) {
// 如果函数执行出错,新的Promise对象的状态为失败
onRejectedNext(err)
}
}
// 封装一个失败时执行的函数
let rejected = error => {
try {
if (!isFunction(onRejected)) {
onRejectedNext(error)
} else {
let res = onRejected(error);
if (res instanceof MyPromise) {
// 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调
res.then(onFulfilledNext, onRejectedNext)
} else {
//否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数
onFulfilledNext(res)
}
}
} catch (err) {
// 如果函数执行出错,新的Promise对象的状态为失败
onRejectedNext(err)
}
}
// 执行对应函数
switch (_status) {
// 当状态为pending时,将then方法回调函数加入执行队列等待执行
case PENDING:
this._fulfilledQueues.push(fulfilled)
this._rejectedQueues.push(rejected)
break
// 当状态已经改变时,立即执行对应的回调函数
case FULFILLED:
fulfilled(_value)
break
case REJECTED:
rejected(_value)
break
}
})
}
完全版–1
ES6语法实现Promise
// 判断变量否为function
const isFunction = variable => typeof variable === ‘function’
// 定义Promise的三种状态常量
const PENDING = ‘PENDING’
const FULFILLED = ‘FULFILLED’
const REJECTED = ‘REJECTED’class MyPromise {
constructor (handle) {
if (!isFunction(handle)) {
throw new Error(‘MyPromise must accept a function as a parameter’)
}
// 添加状态
this._status = PENDING
// 添加状态
this._value = undefined
// 添加成功回调函数队列
this._fulfilledQueues = []
// 添加失败回调函数队列
this._rejectedQueues = []
// 执行handle
try {
//class是严格模式,如果不bind会Uncaught TypeError: Cannot read property undefined
handle(this._resolve.bind(this), this._reject.bind(this))
} catch (err) {
this._reject(err)
}
}
// 添加resovle时执行的函数
_resolve (val) {
const run = () => {
//不是进行状态,已凝固直接返回
if (this._status !== PENDING) return
// 依次执行成功队列中的函数,并清空队列
const runFulfilled = (value) => {
let cb;
while (cb = this._fulfilledQueues.shift()) {
cb(value)
}
}
// 依次执行失败队列中的函数,并清空队列
const runRejected = (error) => {
let cb;
while (cb = this._rejectedQueues.shift()) {
cb(error)
}
}
/* 如果resolve的参数为Promise对象,则必须等待该Promise对象状态改变后,
当前Promsie的状态才会改变,且状态取决于参数Promsie对象的状态
/
if (val instanceof MyPromise) {
val.then(value => {
this._value = value
this._status = FULFILLED
runFulfilled(value)
}, err => {
this._value = err
this._status = REJECTED
runRejected(err)
})
} else {
this._value = val
this._status = FULFILLED
runFulfilled(val)
}
}
// 为了支持同步的Promise,这里采用异步调用
setTimeout(run, 0)
}
// 添加reject时执行的函数
_reject (err) {
if (this._status !== PENDING) return
// 依次执行失败队列中的函数,并清空队列
const run = () => {
this._status = REJECTED
this._value = err
let cb;
//将删除的第一个元素的值赋值给cb
while (cb = this._rejectedQueues.shift()) {
cb(err)
}
}
// 为了支持同步的Promise,这里采用异步调用
setTimeout(run, 0)
}
// 添加then方法
then (onFulfilled, onRejected) {
const { _value, _status } = this
// 返回一个新的Promise对象
return new MyPromise((onFulfilledNext, onRejectedNext) => {
// 封装一个成功时执行的函数
let fulfilled = value => {
try {
if (!isFunction(onFulfilled)) {
onFulfilledNext(value)
} else {
let res = onFulfilled(value);
if (res instanceof MyPromise) {
// 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调
res.then(onFulfilledNext, onRejectedNext)
} else {
//否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数
onFulfilledNext(res)
}
}
} catch (err) {
// 如果函数执行出错,新的Promise对象的状态为失败
onRejectedNext(err)
}
}
// 封装一个失败时执行的函数
let rejected = error => {
try {
if (!isFunction(onRejected)) {
onRejectedNext(error)
} else {
let res = onRejected(error);
if (res instanceof MyPromise) {
// 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调
res.then(onFulfilledNext, onRejectedNext)
} else {
//否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数
onFulfilledNext(res)
}
}
} catch (err) {
// 如果函数执行出错,新的Promise对象的状态为失败
onRejectedNext(err)
}
}
switch (_status) {
// 当状态为pending时,将then方法回调函数加入执行队列等待执行
case PENDING:
this._fulfilledQueues.push(fulfilled)
this._rejectedQueues.push(rejected)
break
// 当状态已经改变时,立即执行对应的回调函数
case FULFILLED:
fulfilled(_value)
break
case REJECTED:
rejected(_value)
break
}
})
}
// 添加catch方法
catch (onRejected) {
return this.then(undefined, onRejected)
}
// 添加静态resolve方法
static resolve (value) {
// 如果参数是MyPromise实例,直接返回这个实例
if (value instanceof MyPromise) return value
return new MyPromise(resolve => resolve(value))
}
// 添加静态reject方法
static reject (value) {
return new MyPromise((resolve ,reject) => reject(value))
}
// 添加静态all方法
static all (list) {
return new MyPromise((resolve, reject) => {
/*
* 返回值的集合
*/
let values = []
let count = 0
for (let [i, p] of list.entries()) {
// 数组参数如果不是MyPromise实例,先调用MyPromise.resolve
this.resolve§.then(res => {
values[i] = res
count++
// 所有状态都变成fulfilled时返回的MyPromise状态就变成fulfilled
if (count === list.length) resolve(values)
}, err => {
// 有一个被rejected时返回的MyPromise状态就变成rejected
reject(err)
})
}
})
}
// 添加静态race方法
static race (list) {
return new MyPromise((resolve, reject) => {
for (let p of list) {
// 只要有一个实例率先改变状态,新的MyPromise的状态就跟着改变
this.resolve§.then(res => {
resolve(res)
}, err => {
reject(err)
})
}
})
}
finally (cb) {
return this.then(
value => MyPromise.resolve(cb()).then(() => value),
reason => MyPromise.resolve(cb()).then(() => { throw reason })
);
}
}
注释:
1.Try
2.consturctor
完全版-2
ES5语法实现
(function () {
// 判断function
function isFunction(fn) {
return typeof fn === ‘function’;
}
// 状态 pending、fulfilled、rejected
var PENDING = 'pending';
var FULFILLED = 'fulfilled';
var REJECTED = 'rejected';
// 构造方法
var Kromise = function (handle) {
// 当前状态
this._status = PENDING;
// 添加成功回调队列
this._fulfilledQueue = [];
// 添加失败回调队列
this._rejectedQueue = [];
// 引用当前this对象
var self = this;
if (!isFunction(handle)) {
throw new Error('Parameter handle is not a function!')
}
// 添加resolve时执行的函数
function _resolve(val) {
var run = function () {
if (self._status !== PENDING) return;
// 依次执行成功队列中的函数,并清空队列
var runFulfilled = function (res) {
var resolve;
while (resolve = self._fulfilledQueue.shift()) { // 出栈
resolve(res);
}
};
// 依次执行失败队列中的函数,并清空队列
var runRejected = function (err) {
var reject;
while (reject = self._rejectedQueue.shift()) { // 出栈
reject(err);
}
};
/* 如果resolve的参数为Kromise对象,则必须等待该Kromise对象状态改变后,
* 当前Kromise的状态才会改变,且状态取决于参数Kromise对象的状态
*/
if (val instanceof Kromise) {
val.then(function (value) {
self._status = FULFILLED;
self._value = value;
runFulfilled(value)
}, function (err) {
self._status = REJECTED;
self._value = err;
runRejected(err);
})
} else {
self._status = FULFILLED;
self._value = val;
runFulfilled(val);
}
};
// 为了支持同步的Promise,这里采用异步调用
setTimeout(run, 0)
}
// 添加reject时执行的函数
function _reject(err) {
var run = function () {
if (self._status !== PENDING) return;
// 依次执行成功队列中的函数,并清空队列
self._status = REJECTED;
self._value = err;
var reject;
while (reject = self._fulfilledQueue.shift()) { // 出栈
reject(err);
}
};
// 为了支持同步的Promise,这里采用异步调用
setTimeout(run, 0)
}
// 执行handle,捕获异常
try {
handle(_resolve.bind(this), _reject.bind(this));
} catch (e) {
_reject(e);
}
};
// 属性
Kromise.length = 1;
// 实例方法
// 实现then方法
Kromise.prototype.then = function (onFulfilled, onRejected) {
var self = this;
// 返回一个新的Kromise对象
return new Kromise(function (onFulfilledNext, onRejectedNext) {
// 成功时的回调
var fulfilled = function (val) {
try {
// 如果不是函数,值穿透
if (!isFunction(onFulfilled)) {
onFulfilledNext(val)
} else {
var res = onFulfilled(val);
// 如果当前回调函数返回Kromise对象,必须等待其状态改变后在执行下一个回调
if (res instanceof Kromise) {
res.then(onFulfilledNext, onRejectedNext);
} else {
//否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数
onFulfilledNext(res);
}
}
} catch (e) {
// 如果函数执行出错,新的Kromise对象的状态为失败
onRejectedNext(e);
}
};
// 失败时的回调
var rejected = function (err) {
try {
if (!isFunction(onRejected)) {
onRejectedNext(err)
} else {
var res = onRejected(err);
if (res instanceof Kromise) {
res.then(onFulfilledNext, onRejectedNext);
} else {
onFulfilledNext(res);
}
}
} catch (e) {
onRejectedNext(e)
}
};
switch (self._status) {
// 当状态为pending时,将then方法回调函数加入执行队列等待执行
case PENDING:
self._fulfilledQueue.push(fulfilled);
self._rejectedQueue.push(rejected);
break;
// 当状态已经改变时,立即执行对应的回调函数
case FULFILLED:
fulfilled(self._value);
break;
case REJECTED:
rejected(self._value);
break;
}
});
};
// 实现catch方法
Kromise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected);
};
// 实现finally方法
Kromise.prototype.finally = function (onFinally) {
return this.then(function (value) {
Kromise.resolve(onFinally()).then(function () {
return value;
})
}, function (err) {
Kromise.resolve(onFinally()).then(function () {
throw new Error(err);
})
})
};
// 静态方法
// 实现resolve方法
Kromise.resolve = function (value) {
// 如果参数是Kromise实例,直接返回这个实例
if (value instanceof Kromise) {
return value;
}
return new Kromise(function (resolve) {
resolve(value)
})
};
// 实现reject方法
Kromise.reject = function (value) {
return new Kromise(function (resolve, reject) {
reject(value)
})
};
// 实现all方法
Kromise.all = function (arr) {
var self = this;
return new Kromise(function (resolve, reject) {
var values = [];
for (var i = 0, len = arr.length; i < len; i++) {
// 数组参数如果不是Kromise实例,先调用Kromise.resolve
self.resolve(arr[i]).then(function (res) {
values.push(res);
// 所有状态都变成fulfilled时返回的Kromise状态就变成fulfilled
if (values.length === arr.length) {
resolve(values);
}
}, function (e) {
// 有一个被rejected时返回的Kromise状态就变成rejected
reject(e);
})
}
})
};
// 实现race方法
Kromise.race = function (arr) {
var self = this;
return new Kromise(function (resolve, reject) {
for (var i = 0, len = arr.length; i < len; i++) {
// 只要有一个实例率先改变状态,新的Kromise的状态就跟着改变
self.resolve(arr[i]).then(function (res) {
resolve(res);
}, function (err) {
reject(err);
})
}
})
};
// 实现any方法
Kromise.any = function (arr) {
var self = this;
return new Kromise(function (resolve, reject) {
var count = 0;
var errors = [];
for (var i = 0, len = arr.length; i < len; i++) {
// 只要有一个实例状态变为fulfilled,新的Kromise状态就会改变为fulfilled
self.resolve(arr[i]).then(function (res) {
resolve(res);
}, function (err) {
errors[count] = err;
count++;
// 否则等待所有的rejected,新的Kromise状态才会改变为rejected
if (count === arr.length) {
reject(errors);
}
})
}
})
};
// 实现allSettled方法
Kromise.allSettled = function (arr) {
var results = [];
var len = arr.length;
for (var i = 0; i < len; i++) {
this.resolve(arr[i]).then(function (res) {
results.push({status: FULFILLED, value: res});
}, function (err) {
results.push({status: REJECTED, value: err});
})
}
// 一旦结束,状态总是`fulfilled`,不会变成`rejected`
return new Kromise(function (resolve, reject) {
resolve(results)
})
};
// 实现try方法
Kromise.try = function (fn) {
if (!isFunction(fn)) return;
return new Kromise(function (resolve, reject) {
return resolve(fn());
})
};
// 挂载
window.Kromise = Kromise;