以前学习写的笔记,感觉还不错,当初收回来,心愿对你有帮忙。
1. 前置常识
1.1 区别实例对象与函数对象
实例对象:new
函数产生的对象, 称为实例对象, 简称为对象
函数对象: 将函数作为对象应用时, 简称为函数对象
function Fn() {}const fn = new Fn() // fn为实例对象Fn.bind({}) // Fn为函数对象
1.2 两种类型的回调函数
同步回调
- 了解:立刻执行, 齐全执行完了才完结, 不会放入回调队列中
- 例子: 数组遍历相干的回调函数 / Promise 的 excutor 函数
异步回调
- 了解:不会立刻执行, 会放入回调队列中未来执行
- 例子:定时器回调 / ajax 回调 / Promise 的胜利|失败的回调
const arr = [1, 2, 3]arr.forEach(item => console.log(item)) // 同步回调, 不会放入回调队列, 而是立刻执行console.log('forEatch()之后')setTimeout(() => { // 异步回调, 会放入回调队列, 所有同步执行完后才可能执行 console.log('timout 回调')}, 0)console.log('setTimeout 之后')
1.3 JS的error解决
谬误的类型
- Error:所有谬误的父类型
ReferenceError:援用的变量不存在
console.log(a) // ReferenceError: a is not defined
TypeError:数据类型不正确的谬误
let b = nullconsole.log(b.xxx) // TypeError: Cannot read property 'xxx' of null
RangeError:数据值不在其所容许的范畴内
function fn() { fn()}fn() // RangeError: Maximum call stack size exceeded
SyntaxError:语法错误
let c = """" // SyntaxError: Unexpected string
错误处理
- 捕捉谬误:try ... catch
- 抛出谬误:throw error
error 对象的构造
- message 属性:谬误相干信息
- stack 属性:函数调用栈记录信息
2. Promise 是什么?
2.1 了解
形象表白:Promise 是JS中进行异步编程的新的解决方案(旧的是谁?=> 纯回调的模式)
具体表白:
- 从语法上来说:Promise 是一个构造函数
- 从性能上来说:Promise 对象用来封装一个异步操作并能够获取其后果
2.2 Promise的状态扭转
Promise的状态扭转只有这2种:
且一个 Promise 对象只能扭转一次,无论变成胜利还是失败,都会有一个后果数据,胜利的后果数据个别称为 value
,失败的后果数据个别称为 reason
。
2.3 Promise根本流程
2.4 Promise的根本应用
示例,如果以后工夫是偶数就代表胜利,否则代表失败
// 1. 创立一个新的Promise对象const p = new Promise((resolve, reject) => { // 执行器函数,同步执行 // 2. 执行异步操作工作 setTimeout(() => { const time = Date.now() // 如果以后工夫是偶数就代表胜利,否则代表失败 // 3.1 如果胜利了,调用resolve(value) if (time % 2 === 0) { resolve('胜利的数据,value = ' + time) } else { // 3.2 如果失败了,调用reject(reason) reject('失败的数据,reason = ' + time) } }, 1000);})p.then(value => { // 承受失去胜利的value数据,专业术语:onResolved console.log('胜利的回调', value)}, reason => { // 承受失去失败的reason数据,专业术语:onRejected console.log('失败的回调', reason)})
3. 为什么要用Promise?
3.1 指定回调函数的形式更加灵便
旧的:回调函数必须在启动异步工作前指定
// 胜利的回调函数function successCallback(result) { console.log('解决胜利:' + result)}function failureCallback(error) { console.log('解决失败:' + error)}// 应用纯回调函数createAudioFileSync(audioSettings, successCallback, failureCallback)
Promise:启动异步工作 => 返回 Promise 对象 => 给 Promise 对象绑定回调函数,甚至能够在异步工作完结后指定多个
// 应用 Promiseconst promise = createAudioFileSync(audioSettings)setTimeout(() => { promise.then(successCallback, failureCallback)}, 3000);
3.2 反对链式调用,能够解决回调天堂问题
什么是回调天堂?回调函数嵌套调用,内部回调函数异步执行的后果是嵌套的回掉执行条件,代码是程度向右扩大
// 回调天堂doSomething(function(result) { doSomethingElse(result, function(newResult) { doThirdThing(newResult, function(finalResult) { console.log('Got the final result: ' + finalResult) }, failureCallback) }, failureCallback)},
回调天堂的毛病:不便浏览,不便于异样解决
解决方案:Promise 链式调用,代码程度向下扩大
doSomething().then(function(result) { return doSomethingElse(result)}).then(function(newResult) { return doThirdThing(newResult)}).then(function(finalResult) { console.log('Got the final result: ' + finalResult)}).catch(failureCallback)
终极解决方案: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) }}
4. Promise的API阐明
4.1 API 阐明
Promise 构造函数。
Promise (excutor) {}
,excutor 会在 Promise 外部立刻同步回调,异步操作在执行器中执行
- excutor 函数:执行器
(resolve, reject) => {}
- resolve 函数:外部定义胜利时咱们调用的函数
value => {}
- reject 函数:外部定义失败时咱们调用的函数
reason => {}
Promise.prototype.then办法
(onResolved, onRejected) => {}
,指定用于失去胜利 value 的胜利回调和用于失去失败 reason 的失败回调返回一个新的 promise 对象
- onResolved 函数:胜利的回调函数
(value) => {}
- onRejected 函数:失败的回调函数
(reason) => {}
Promise.prototype.catch 办法
(onRejected) => {}
,onRejected 函数:失败的回调函数 (reason) => {}
,then() 的语法糖, 相当于: then(undefined, onRejected)
Promise.resolve办法
(value) => {}
,value:胜利的数据或 promise 对象,返回一个胜利/失败的 promise 对象
Promise.reject办法
(reason) => {}
,reason:失败的起因,返回一个失败的 promise 对象
Promise.all办法
(promises) => {}
,promises:蕴含 n 个 promise 的数组,返回一个新的 promise, 只有所有的 promise 都胜利才胜利, 只有有一个失败了就间接失败
Promise.race办法
(promises) => {}
,promises: 蕴含 n 个 promise 的数组,返回一个新的 promise, 第一个实现的 promise 的后果状态就是最终的后果状态
// 产生一个胜利值为 1 的 Promise 对象const p1 = new Promise((resolve, reject) => { resolve(1)})// 产生一个胜利值为 2 的 Promise 对象const p2 = Promise.resolve(2)// 产生一个失败值为 3 的 Promise 对象const p3 = Promise.reject(3)p1.then(value => console.log(value))p2.then(value => console.log(value))p3.catch(reason => console.error(reason))// const pAll = Promise.all([p1, p2])const pAll = Promise.all([p1, p2, p3])pAll.then(values => { console.log('all onResolved()', values) // all onResolved() [ 1, 2 ]}, reason => { console.log('all onRejected()', reason) // all onRejected() 3})const race = Promise.race([p1, p2, p3])race.then(value => { console.log('all onResolved()', value) }, reason => { console.log('all onRejected()', reason) })
4.2 Promise的几个关键问题
4.2.1 如何扭转Promise的状态
resolve(value),如果以后是 pendding 就会变为 resolved
reject(reason),如果以后是 pendding 就会变为 rejected
抛出异样,如果以后是 pendding 就会变为 rejected
const p = new Promise((resolve, reject) => { // resolve(1) // Promise 变为 resolved 胜利状态 // reject(2) // Promise 变为 rejected 失败状态 // Promise 变为 rejected 失败状态,reason为抛出的 error throw new Error('我抛出的异样') // 变为 rejected 失败状态,reason为抛出的 3 // throw 3})p.then( value => {}, reason => { console.log('reason :', reason); })
4.2.2 当一个promise指定多个胜利/失败回调函数, 都会调用吗?
当 promise 扭转为对应状态时都会调用
const p = new Promise((resolve, reject) => { // 变为 rejected 失败状态,reason为抛出的 3 throw 3})p.then( value => {}, reason => { console.log('reason :', reason); })p.then( value => {}, reason => { console.log('reason2 :', reason); })// 后果:// reason : 3// reason2 : 3
4.2.3 扭转promise状态和指定回调函数谁先谁后?
都有可能, 失常状况下是先指定回调再扭转状态, 但也能够先改状态再指定回调。
如何先改状态再指定回调?
- 在执行器中间接调用 resolve()/reject()
- 提早更长时间才调用 then()
什么时候能力失去数据?
- 如果先指定的回调, 那当状态产生扭转时, 回调函数就会调用, 失去数据
- 如果先扭转的状态, 那当指定回调时, 回调函数就会调用, 失去数据
// 惯例:先指定回调函数,后扭转状态new Promise((resolve, reject) => { setTimeout(() => { resolve(1) // 后扭转状态(同时指定数据),异步执行回调函数 }, 1000);}).then( // 先指定回调函数,保留以后指定的回调函数 value => {}, reason => { console.log('reason :', reason); })// 先改状态,后指定回调函数new Promise((resolve, reject) => { resolve(1) // 先扭转状态(同时指定数据)}).then( // 后指定回调函数,异步执行回调函数 value => { console.log('value2:', value);}, reason => { console.log('reason2 :', reason); })const p = new Promise((resolve, reject) => { resolve(1) // 先扭转状态(同时指定数据)})setTimeout(() => { p.then( value => { console.log('value3:', value);}, reason => { console.log('reason3 :', reason); } )}, 1500);
4.2.4 promise.then()返回的新 promise 的后果状态由什么决定?
简略表白:由 then()指定的回调函数执行的后果决定
具体表白:
- 如果抛出异样, 新 promise 变为 rejected, reason 为抛出的异样
- 如果返回的是非 promise 的任意值, 新 promise 变为 resolved, value 为返回的值
- 如果返回的是另一个新 promise, 此 promise 的后果就会成为新 promise 的后果
new Promise((resolve, reject) => { resolve(1)}).then( value => { console.log('onResolved1()', value); // 1 // return 1.1 或 return Promise.resolve(1.1) // return Promise.reject(1.1) // throw 1.1 }, reason => { console.log('onRejected1()', reason); }).then( value => { console.log('onResolved2()', value); }, // 1.1 reason => { console.log('onRejected2()', reason) } // 1.1)
4.2.5 promise 如何串连多个操作工作
promise 的 then()
返回一个新的 promise, 能够开成 then()
的链式调用,通过 then 的链式调用串连多个同步/异步工作。
4.2.6 promise 异样传透
当应用 promise 的 then 链式调用时, 能够在最初指定失败的回调,后面任何操作出了异样, 都会传到最初失败的回调中解决。
上面的示例代码演示了异样传透
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('onRejected()', reason); // onRejected() 1 })
代码会执行 .catch
中的代码,但实际上代码的执行不是执行到第 3 行就间接跳转到 catch 外面了,而是从第一个 then 调用向下一个个的执行(逐级传递),然而因为咱们 then 外面没有解决异样。在 then 外面没写解决异样实际上相当于默认增加了 reason => { throw reason }
或者 reason => Promise.reject(reason)
:
new Promise((resolve, reject) => { reject(1)}).then( value => { console.log('onResolved1()', value); }, // reason => { throw reason } // 或者 reason => Promise.reject(reason))
Promise的异样传透示意图
4.2.7 中断 promise 链
当应用 promise 的 then 链式调用时, 在两头中断, 不再调用前面的回调函数。
方法: 在回调函数中返回一个 pendding
状态的 promise 对象
new Promise((resolve, reject) => { resolve(1)}).then( value => { console.log('onResolved1()', value); return new Promise(() => {}) // 返回一个 pending 的 Promise,中断 promise 链 }).then( // 这个 then 不会执行力 value => { console.log('onResolved2()', value); })
5. async与await
Async/await 实际上只是一种基于promises的糖衣语法糖,Async/await 和 promises一样,都是非梗塞式的,Async/await 让异步代码更具同步代码格调,这也是其劣势所在。
async function
用来定义一个返回AsyncFunction
对象的异步函数。异步函数是指通过事件循环异步执行的函数,它会通过一个隐式的Promise
返回其后果,。如果你在代码中应用了异步函数,就会发现它的语法和构造会更像是规范的同步函数。MDN async_functionawait
操作符用于期待一个Promise
对象。它只能在异步函数async function
中应用。MDN await
5.1 async函数
async
函数的返回值为 Promise
对象,async
函数返回的 Promise
的后果由函数执行的后果决定
async function fn1() { return 1}const result = fn1()console.log(result) // Promise { 1 }
在控制台能够看见如下信息
既然是Promise对象,那么咱们用 then 来调用,并抛出谬误,执行 onRejected()
且 reason 为错误信息为“我是谬误”
async function fn1() { // return 1 // return Promise.resolve(1) // return Promise.reject(2) throw '我是谬误'}fn1().then( value => { console.log('onResolved()', value) }, reason => { console.log('onRejected()', reason) } // onRejected() 我是谬误)
5.2 await表达式
await
右侧的表达式个别为 promise
对象, 但也能够是其它的值:
- 如果表达式是
promise
对象,await
返回的是promise
胜利的值 - 如果表达式是其它值, 间接将此值作为
await
的返回值
function fn2() { return new Promise((resolve, reject) => { setTimeout(() => { resolve(1000) }, 1000); })}function fn4() { return 6 }async function fn3() { // const value = await fn2() // await 右侧表达式为Promise,失去的后果就是Promise胜利的value // const value = await '还能够这样' const value = await fn4() console.log('value', value)}fn3() // value 6
await
必须写在 async
函数中, 但 async
函数中能够没有 await
,如果 await
的 Promise
失败了, 就会抛出异样, 须要通过 try...catch
捕捉解决
function fn2() { return new Promise((resolve, reject) => { setTimeout(() => { // resolve(1000) reject(1000) }, 1000); })}async function fn3() { try { const value = await fn2() } catch (error) { console.log('失去失败的后果', error) }}fn3() // 失去失败的后果 1000
5.3 Async/await 比 Promise 更优越的体现
简洁洁净,应用async/await能省去写多少行代码
错误处理,async/wait 能用雷同的构造和好用的经典 try/catch 解决同步和异步谬误,谬误堆栈能指出蕴含谬误的函数。
调试,async/await 的一个极大劣势是它更容易调试,应用async/ await则无需过多箭头函数,并且能像失常的同步调用一样间接跨过await调用。
笔记首发于我的公众号《前端全栈开发者》