1.1 实例对象和函数对象
- 实例对象:new 函数产生对象,称为实例对象简称对象。
- 函数对象:将函数作为对象使用时,称为函数对象。
function Func() { // Func只能称为函数
}
const func = new Func(); // Fn只能new过的才可以称为构造函数
// func称为实例对象
console.log(func.prototype); // 函数对象
1.2 两种典型的回调函数
1. 同步回调
立即执行,完全执行完了才会结束,不会放入回调队列中
const arr = [1, 3, 5];
arr.forEach(item => { // 遍历回调,同步回调,不会放入队列中一上来就会执行
console.log(item);
});
console.log("forEach()执行完毕之后");
2. 异步回调
不会立即执行,会放入回调队列中将来执行
eg: setTimeout、setInterval、setImmediate、Ajax请求、Script脚本、Promise函数
// 定时器回调
setTimeout(() => { // 异步回调,会放入队列中将来执行
console.log("timeout callback()');
}, 0);
console.log("setTimeout()之后");
// Promise成功或失败的回调
new Promise((resolve, reject) => {
}).then(
value => {console.log("value", value)},
reason => {console.log("reason", reason)},
)
console.log(".....");
JS引擎先把初始化的同步代码都执行完成之后,才执行回调队列中的代码 (执行时机:同步代码 > 回调队列)
1.3 JavaScript中异常error处理
1. 错误的类型
- Error: 所有错误的父类型
- ReferenceError: 引用的变量不存在
console.log(a); // ReferenceError:a
- TypeError: 数据类型不正确
let b;
console.log(b.xxx);
// TypeError: Cannot read property 'xxx' of undefined
let c = {};
c.xxx();
// TypeError: c.xxx is not a function
- RangeError: 数据值不在其所允许的范围内
function fn() {
fn();
}
fn()
// RangeError: MAximum call stack size exceeded
- SyntaxError: 语法错误
const c = """";
// SyntaxError: Unexpected string
2. 错误处理(捕获与抛出)
抛出错误:throw error
function something() {
if(Date.now() % 2 === 1 ) {
console.log("当前时间为奇数, 可以执行任务");
} else {
throw new Error("当前时间为偶数,无法执行任务");
}
}
捕获错误:try ... catch
try {
something();
} catch (error) {
alert(error.message);
}
3. 错误对象
- message属性:错误相关信息
- stack属性:函数调用栈记录信息
try {
let d;
console.log(d.xxx);
} catch (error) {
console.log(error.message);
console.log(error.stack);
}
console.log("出错之后");
// Cannnot read property "xxx" of undefined
// TypeError: Cannot read property "xxx" of undefined
// 出错之后
因为错误被捕获处理,后面的代码运行下去,打印出错之后
Promise的理解和使用
Promise是什么?
简单来说:Promise是JS中异步编程的解决方案,传统采用回调来实现异步编程,缺点:回调地狱问题。
具体表达:
- Promise本质上是一个构造函数里面包含all、race、reject、resolve等方法,原型上则包含then、catch、finally等方法。
- Promise功能上是用来封装一个异步操作并获取其成功/失败的值。
Promise的状态?
实例对象Promise中的一个属性PromiseState
pending、resolved/fulfilled、rejected
状态变换有两种方式:
- pending => fulfiled(已完成)
- pending => rejected(已失败)
注意项:
- 外界的状态不受外界影响。
- 只有这两种,且一个promise对象只能改变一次。
- 一旦状态改变,就不会再变,任何时候都可以得到这个结果。
- 无论成功还是失败,都会有一个结果数据。成功的结果称之为【value】 失败的结果称之为【reason】
Promise对象的值
实例对象Promise的另一个值是PromiseResult,保存对象成功/失败的值(value/reason)
Promise的基本流程
const promise = new Promise(function(resolve, reject){
// ... some code
if(异步操作成功) {
resolve(value);
} else {
reject(reason);
}
});
Promise构造函数接收一个函数(执行器函数)作为参数,该函数的两个参数分别是resolve和reject。
他们是两个函数,有JS引擎提供,不用自己部署。
resolve函数作用:
将Promise对象的状态从【未完成】变为【成功】即从pending变为resolved
在异步操作成功的时候调用,并将异步操作的结果作为参数value传递出去。
reject函数作用:
将Promise对象的状态从【未完成】变为【失败】即从pending变为rejected
在异步操作失败的时候调用,并将异步操作报出的错位,作为参数error/reason传递出去。
Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。
promise.then(function(value) {
// success
}, function(reason) {
});
then方法可以接收两个回调函数作为参数。
第一个回调函数onResolved()是Promise对象的状态变为resolved的时候调用。
第二个回调函数onRejected()是Promise对象的状态变为rejected的时候调用。
两个函数可选不一定要提供,都接收Promise对象传出的值作为参数。
<script>
// 创建一个新的p对象promise
// 执行器函数
const p = new Promise((resolve, reject) => {
// 执行异步操作任务
setTimeout(() => {
const time = Date.now();
// 如果当前时间是偶数代表成功,否则失败
if (time % 2 === 0) {
// 如果成功调用resolve(value)
resolve("成功的数据, time = " + time);
} else {
resolve("失败的数据, time = " + time);
}
}, 1000);
})
p.then((value) => {
// 接收得到成功的value数据 onResolved
console.log("成功回调:", value);
}, (reason) => {
// 接收得到失败的reason数据 onRejected
console.log("失败回调:", reason);
})
</script>
.then()和执行器(executor)同步执行,.then()中的回调函数异步执行
2.2 为什么要使用Promise?
1. 指定回调函数的方式更加灵活
旧的:必须在启动异步任务之前指定
// 纯回调的方式
// 成功的回调函数
function successCallback(result) {
console.log("声音文件创建成功:" + result);
}
// 失败的回调函数
function failureCallback(error) {
console.log("声音文件创建失败:" + error);
}
// 必须指定回调函数,再执行异步任务
createAudioFileAsync(audioSettings, successCallback, failureCallback); // 回调函数在执行异步任务(函数)之前就需要指定
Promise: 启动异步任务 =》 返回Promise对象 =》 给Promise对象绑定回调函数(甚至可以在异步任务结束之后指定)
// 使用Promise
const promise = createAudioFileAsync(audioSettings); // 执行2秒
setTimeout(() => {
promise.then(successCallback, failureCallback); // 也可以获取
}, 3000);
2. 支持链式调用,可以解决回调地狱问题
什么是回调地狱?
回调函数嵌套调用,外部回调函数异步执行的结果是其内部嵌套的回调函数执行的条件。
doSomething(function(result) {
doSomethingElse(result, function(newReuslt){
doThirdThing(newResult, function(finalResult){
console.log("Got the final result: " + finalResult);
}, failureCallback)
}, failureCallback)
}, failureCallback)
回调地狱的缺点?
- 不便于阅读
- 不便于异常处理
解决方法?
- Promise链式调用
使用Promise的链式调用解决回调地狱问题
doSomething()
.then(result => doSomethingElse(result))
.then(newResult => doThirdThing(newResult))
.then(finalResult => {console.log("Got the final result: " + finalResult)})
.catch(failureCallback);
终极解决方案?
- async/await
回调地狱终极解决方案 async/await
async function request() {
try {
const result = await doSomething();
const newResult = await doSomethingElse(result);
const finalResult = await doThirdThing(newResult);
console.log("Got the final result: " + finalResult);
} catch (error) {
failureCallback(error);
}
}
2.3 如何使用Promise
1. Promise构造函数: Promise(executor) {}
- executor函数:同步执行(resolve, reject) => {}
- resolve函数:内部定义成功时调用的函数 resolve(value);
- reject函数:内部定义失败时调用的函数 reject(reason);
说明: executor是执行器,会在Promise内部立即同步回调,异步操作resolve/reject就在executor中执行
2. Promise.prototype.then方法: p.then(onResolved, onRejected) 指定两个回调(成功 + 失败)
- onResolved函数:成功的回调函数(value) => {}
- onRejected函数:失败的回调函数(reason) => {}
说明:指定用于得到成功value的成功回调和用于得到失败reason的失败回调,返回一个新的Promise对象。
3. Promise.prototype.catch方法:p.catch(onRejected) 指定失败的回调
- onRejected函数:失败的回调函数(reason) => {}
说明: then()的语法糖,相当于then(undefined, onRejected)
new Promise((resolve, reject) => {
setTimeout(() => {
if(...) {
resolve("成功的数据"); // resolve()函数
} else {
reject("失败的数据"); // reject()函数
}
}, 1000)
}).then(
value => { // onResolved()函数
console.log(value); // 成功的数据
}
).catch(
reason => { // onRejected()函数
console.log(reason); // 失败的数据
}
);
4. Promise.resolve()方法:Promise.resolve(value)
value: 将被Promise对象解析的参数,也可以是一个成功或失败的Promise对象
返回:返回一个带着定值解析过的Promise对象,如果参数本身就是一个Promise对象,则直接返回这个Promise对象。
- 如果传入的参数未非Promise类型的对象,则返回的结果为成功Promise对象
let p1 = Promise.resolve(521);
console.log(p1); // Promise {<fulfilled>: 521}
- 如果传入的参数为Promise对象,则参数的结果决定了resolve的结果
let p2 = Promise.resolve(new Promise((resolve, reject) => {
// 参数的结果决定返回的结果
// resolve("OK"); // 成功的Promise
reject("Error"); // 失败的Promise
}));
console.log(p2);
p2.catch(reason => {
console.log(reason);
});
- Promise.resolve()/Promise.reject()方法是一个语法糖用来快速得到Promise对象
// 产生一个成功值为1的Promise对象
new Promise((resolve, reject) => {
resolve(1);
});
// 相当于
const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);
const p3 = Promise.resolve(3);
p1.then(value => {console.log(value)}); // 1
p2.then(value => {console.log(value)}); // 2
p3.then(reason => {console.log(reason)}); // 3
Promise.all方法: Promise.all(iterable)
iterable: 包含n个promise的可迭代对象,eg: Array或String
说明: 返回一个新的promise,只有所有的promise都成功才能成功,只要有一个失败了则就直接失败。
let p1 = new Promise((resolve, reject) => {
resolve("OK");
});
let p2 = Promise.resolve("Success");
let p3 = Promise.resolve("Oh Yeah");
const result = Promise.all([p1, p2, p3]);
console.log(result);
Promise.all()使用案例
const p1 = Promise.resolve(1)
const p2 = Promise.resolve(2)
const p3 = Promise.reject(3)
const pAll = Promise.all([p1, p2, p3])
const pAll2 = Promise.all([p1, p2])
//因为其中p3是失败所以pAll失败
pAll.then(
value => {
console.log('all onResolved()', value)
},
reason => {
console.log('all onRejected()', reason)
}
)
// all onRejected() 3
pAll2.then(
values => {
console.log('all onResolved()', values)
},
reason => {
console.log('all onRejected()', reason)
}
)
// all onResolved() [1, 2]
7. Promise.race方法: Promise.race(iterable)
iterable: 包含n个promise的可迭代对象,eg:Array或String
DESC:返回一个新的Promise,第一个完成的Promise的结果状态就是最终的结果状态,谁先完成就输出谁(不管是成功还是失败)
const pRace = Promise.race([p1, p2, p3]);
// 谁先完成就输出谁(不管是成功还是失败)
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 1000);
});
const p2 = Promise.resolve(2);
const p3 = Promise.reject(3);
pRace.then(
value => {
console.log('race onResolved()', value);
},
reason => {
console.log('race onRejected()', reason);
});
// race onResolved() 2
Promise.race()使用案例
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("OK");
}, 1000);
});
let p2 = Promise.resolve("Success");
let p3 = Promise.resolve("Oh Yeah");
// 调用
const result = Promise.race([p1, p2, p3]);
console.log(result);
Promise的几个关键问题
1. 如何改变Promise的状态
- resolve(value): 如果当前是pending就会变为resolved
- reject(reason): 如果当前是pending就会变为rejected
- 抛出异常:如果当前是pending就会变为rejected
const p = new Promise((resolve, reject) => {
// resolve(1); 变为resolved成功状态
// reject(2); 变为rejected失败状态
throw new Error("出错了"); // 抛出异常 变为rejected失败状态 reason为抛出的error
})
p.then(
value => {},
reason => {console.log('reason', reason)}
)
2. 一个Promise指定多个成功/失败回调函数,都会调用吗?
当Promise改变为对应状态时都会调用
const p = new Promise((resolve, reject) => {
// resolve(1)
reject(2)
})
p.then(
value => {},
reason => {console.log('reason', reason)}
)
p.then(
value => {},
reason => {console.log('reason2', reason)}
)
// reason 2
// reason2 2
3. 改变Promise状态和指定回调函数谁先谁后?
都有可能,常规时先指定回调再改变状态,但也可以先改变状态再指定回调
- 如何先改变状态再指定回调?
1)在执行器中直接调用resolve()/reject()
- 延迟更长时间才会调用then()
let p = new Promise((resolve, reject) => {
// setTimeout(() => {
resolve("OK");
}, 1000); // 有异步就先指定回调,否则先改变状态
});
p.then(value => {
console.log(value);
}, reason => {
console.log(reason);
});
-
什么时候才能得到数据?
-
如果先指定的回调,当状态发生改变的时候,回调函数就会得到数据;
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1); // 改变状态
}, 1000);
}).then(
value => {},
reason => {}
)
- 如果先改变的状态,那当指定回调时,回调函数就会调用得到数据;
``
new Promise((resolve, reject) => {
resolve(1) // 改变状态
}).then( // 指定回调函数
value => {},
reason =>{}
)
#### Promise如何串联多个操作任务 ?
1) Promise的then()返回一个新的Promise,可以并成then()链式调用
2) 通过then的链式调用串联多个同步/异步任务
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("OK");
}, 1000);
});
p.then(value => {
return new Promise((resolve, reject) => {
resolve("success");
});
}).then(value => {
console.log(value); // Success
}).then(value => {
console.log(value); // undefined
});
##### 链式调用案例2
new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行任务1(异步)')
resolve(1)
}, 1000)
}).then(
value => {
console.log('任务1的结果', value)
console.log('执行任务2(同步)')
return 2 // 同步任务直接return返回结果
}
).then(
value => {
console.log('任务2的结果', value)
return new Promise((resolve, reject) => { // 异步任务需要包裹在Promise对象中
setTimeout(() => {
console.log('执行任务3(异步)')
resolve(3)
}, 1000)
})
}
).then(
value => {
console.log('任务3的结果', value)
}
)
// 执行任务1(异步)
// 任务1的结果 1
// 执行任务2(同步)
// 任务2的结果 2
// 执行任务3(异步)
// 任务3的结果 3
#### Promise异常穿透(传透)?
1) 当使用Promise的then链式调用时,可以在最后指定失败的回调;
2)前面任何操作除了异常,都会传到最后失败的回调中处理;
new Promise((resolve, reject) => {
//resolve(1)
reject(1)
}).then(
value => {
console.log('onResolved1()', value)
return 2
}
).then(
value => {
console.log('onResolved2()', value)
return 3
}
).then(
value => {
console.log('onResolved3()', value)
}
).catch(
reason => {
console.log('onRejected1()', reason)
}
)
// onRejected1() 1
// 或者
new Promise((resolve, reject) => {
//resolve(1)
reject(1)
}).then(
value => {
console.log('onResolved1()', value)
return 2
},
reason => {throw reason} // 抛出失败的结果reason
).then(
value => {
console.log('onResolved2()', value)
return 3
},
reason => {throw reason} // 抛出失败的结果reason
).then(
value => {
console.log('onResolved3()', value)
},
reason => {throw reason} // 抛出失败的结果reason
).catch(
reason => {
console.log('onRejected1()', reason)
}
)
// onRejected1() 1
// 所以失败的结果是一层一层处理下来的,最后传递到 catch 中。
// 或者,将 reason => {throw reason} 替换为 reason => Promise.reject(reason) 也是一样的
# 如何中断Promise的链?
当使用Promise的then链式调用时,在中间中断,不再调用后面的回调函数
办法:在回调函数中返回一个pending状态的promise对象
new Promise((resolve, reject) => {
//resolve(1)
reject(1)
}).then(
value => {
console.log('onResolved1()', value)
return 2
}
).then(
value => {
console.log('onResolved2()', value)
return 3
}
).then(
value => {
console.log('onResolved3()', value)
}
).catch(
reason => {
console.log('onRejected1()', reason)
}
).then(
value => {
console.log('onResolved4()', value)
},
reason => {
console.log('onRejected2()', reason)
}
)
// onRejected1() 1
// onResolved4() undefined
// 为了在catch中就中断执行可以这样写:
new Promise((resolve, reject) => {
//resolve(1)
reject(1)
}).then(
value => {
console.log('onResolved1()', value)
return 2
}
).then(
value => {
console.log('onResolved2()', value)
return 3
}
).then(
value => {
console.log('onResolved3()', value)
}
).catch(
reason => {
console.log('onRejected1()', reason)
return new Promise(() => {}) // 返回一个pending的promise
}
).then(
value => {
console.log('onResolved4()', value)
},
reason => {
console.log('onRejected2()', reason)
}
)
// onRejected1() 1
> 在catch中返回一个新的Promise,且这个Promise没有结果。
> 由于,返回的新的Promise结果决定后面then中的结果,所以后面的then中也没有结果
> 就实现了中断Promise链的效果。
标签:resolve,console,log,value,reason,理解,Promise,使用
From: https://www.cnblogs.com/openmind-ink/p/16971453.html