惠城营销网站制作,企业网站手机网站建设,建立一个网站需要多少钱,wordpress手机侧边导航栏目录
异步编程
回调函数
回调地狱
Promise
基本概念
Promise的特点
1.Promise是一种构造函数
2.Promise接收函数创建实例
3.Promise对象有三种状态
4.Promise状态转变不可逆
5.Promise 实例创建即执行
6.Promise可注册处理函数
7.Promise支持链式调用
Promise的静…目录
异步编程
回调函数
回调地狱
Promise
基本概念
Promise的特点
1.Promise是一种构造函数
2.Promise接收函数创建实例
3.Promise对象有三种状态
4.Promise状态转变不可逆
5.Promise 实例创建即执行
6.Promise可注册处理函数
7.Promise支持链式调用
Promise的静态方法
1.resolve()方法
2.reject()方法 3.all()方法
4.race()方法
5.allSettled() 方法
Promise的实例方法
1.then() 方法
2.catch() 方法 3.finally() 方法
async/await
基本概念
基本用法
async
await
使用示例
async/await 的优势 异步编程
JavaScript 在设计之初就是单线程的这意味着它在同一时间只能执行一个任务然而浏览器和 Node.js 环境都提供了多种机制来允许 JavaScript 代码在不阻塞主线程的情况下执行异步操作。
此处仅以浏览器环境下举例 参考浏览器渲染基本原理
浏览器有三大进程 —— 网络进程浏览器进程和渲染进程。每个窗口开启一个渲染进程。每个渲染进程仅开启一个渲染主线程主线程负责执行代码HTMLCSSJS渲染页面。
所以在浏览器中JS是运行在承担着诸多工作的渲染主线程上的。如果使用同步的方式等待任务结束再执行下一个任务就有可能会造成阻塞浪费主线程的宝贵时间还可能导致页面无法及时更新给用户造成“卡死”现象。
所以采用异步执行来避免当发生耗时任务时渲染主线程会将任务交给其它渲染子线程取处理自身则立即结束任务的执行转而执行后续代码。当其他线程完成处理后会将事先传递的回调函数包装成任务加到消息队列末尾排队等待渲染主线程通过事件循环机制调度执行。
在这种异步模式下浏览器永不阻塞从而最限度的保证了单线程的流畅运行。 举例
setTimeout(function () {console.log(异步任务)
}, 0)
console.log(同步任务)
// 输出顺序 同步任务 异步任务 使用异步方式执行任务在不阻塞主线程的同时还能极大的缩短程序执行所需的时间 该图摘自菜鸟教程中的异步编程小节 回调函数
在JavaScript中回调函数是一段可执行的代码段function它作为一个参数传递给其他的代码其作用是在需要的时候方便调用这段代码简单来说就是函数作为参数传递到另外一个函数中这个作为参数的函数就是回调函数。
回调函数是 JavaScript 异步编程中最早也是最基本的模式。当一个异步操作完成时它会调用事先定义好的回调函数来处理异步操作完成后的结果或响应。
回调函数在异步编程中的作用将异步操作的处理逻辑封装在回调函数中然后在异步操作完成时执行这些逻辑。这有助于将异步代码与同步代码分离使得程序的结构更加清晰。
const success (data) {console.log(请求成功,开始处理 data)//....其他操作
}
const fail (err) {console.log(请求失败开始处理错误 err)//....其他操作
}
//回调函数callback1请求失败时的操作
//回调函数callback2请求成功时的操作
function foo(signal, callback1, callback2) {//模拟异步请求setTimeout(() {if (signal ok) {callback1(data)} else callback2(err)}, 1000)
}
foo(ok, success, fail)
在上面的例子中等待1s后模拟耗时任务根据任务结果此处我用foo()的第一个参数‘ok’代替传递任务结果并调用相应的回调函数。 回调地狱
最简单的网络请求大概是这样
请求1(function callback(请求1的结果) {处理请求1的结果
})
很简单
但是随着需求的变化当我们需要根据第一次请求的结果进行第二次请求时
请求1(function callback(请求结果1) {//根据请求1的结果进行请求2请求2(function callback(请求结果2) {处理请求结果2})
})
也不复杂
直至需求不断变化最终出现了类似下面的情况
请求1(function callback(请求结果1) {//根据请求1的结果进行请求2请求2(function callback(请求结果2) {//根据请求2的结果进行请求3请求3(function callback(请求结果3) {//根据请求3的结果进行请求4请求4(function callback(请求结果4) {//根据请求4的结果进行请求5请求5(function callback(请求结果5) {// ...})})})})
})
这下懵圈了在异步请求和回调函数的不断嵌套下臭名昭著的 回调地狱 诞生了。
试想一下在回调函数内部可能会存在大量的处理逻辑并且每一次的请求结果会成为下一请求的依赖请求又会存在有失败和成功两种情况.....如此一来代码将显得十分臃肿复杂后期为维护将变得十分困难。
回调地狱带来的负面作用
代码臃肿可读性差耦合度过高可维护性差代码复用性差容易滋生 bug只能在回调里处理异常 Promise
基本概念
为了优雅的解决回调地狱的问题在ES6中一种新的异步编程的一种解决方案Promise诞生了。
在JS中Promise是一个代表了异步操作最终完成或失败及其结果值的对象。它允许开发人员为异步操作的成功和失败情况注册处理程序极大地简化了异步编程的复杂性。 Promise的特点
1.Promise是一种构造函数
通过new关键字创建实例对象构造函数自身有allracerejectresolve等静态方法其原型对象上有thencatchfinally等方法。
let promise new Promise(() {})
console.log(typeof Promise)//function
console.log(typeof promise)//object//查看Promise函数对象
console.dir(Promise) 2.Promise接收函数创建实例
创建一个新的Promise实例时必须传递一个函数作为参数给Promise的构造函数它定义了异步操作的逻辑。这个函数被称为执行器executor函数它本身接受两个函数作为参数resolve和reject。这两个参数也是函数由JavaScript引擎提供用于改变Promise的状态。
let promise new Promise((resolve, reject) {})3.Promise对象有三种状态
分别为pending进行中fulfilled已成功和rejected已失败其通过执行器executor函数接收的resolve和reject来改变。 1. new Promise()
let promise new Promise((resolve, reject) {})
console.dir(promise) 新创建的promise实例其状态为pending进行中结果为undefined 2. resolve(value)
let promise new Promise((resolve, reject) {resolve(完成结果值)
})
console.dir(promise)
resolve()接收异步任务执行结果的值作为参数并将promise实例的状态转变为fulfilled已成功结果为 resolve()接收的值 3.rejectedreason
let promise new Promise((resolve, reject) {reject(完成失败原因)
})
console.dir(promise)
rejected()接收异步任务执行失败的原因作为参数并将promise实例的状态转变为rejected已失败结果为 rejected()接收的失败原因 4.Promise状态转变不可逆 Promise 状态的转变是不可逆且只能发生一次且只能由异步操作结果决定。任何其他操作都不能改变这个状态 5.Promise 实例创建即执行
let promise new Promise((resolve, reject) {reject(获取数据失败)
})
创造 promise 实例后它会立即执行的特点所以该段代码运行后会立即抛出一个错误 但如果将其放入函数的私有作用域内由于函数的特性promise仅在函数被调用时才会执行 6.Promise可注册处理函数
可通过.then()和.catch()方法为promise注册处理函数在promise状态改变时调用then和catch的具体用法见下方Promise的实例方法 7.Promise支持链式调用
建议先阅读下方Promise的实例方法。Promise链式调用的核心时then方法由于then方法返回一个新的 Promise实例对象该对象也就可以调用promise的实例方法这使得我们可以继续链式调用其他then()方法。如此一来便可以很容易地处理异步操作的序列。
注意then()的链式调用中下一个依赖于上一个返回结果 举例
function fetchData(url) {return new Promise((resolve, reject) {// 假设这是一个异步请求数据的函数setTimeout(() {if (url) {resolve(数据来自 ${url})} else {reject(URL 不能为空)}}, 1000)})
}
// 链式调用
fetchData(https://example.com).then((data) {console.log(data) // 输出数据来自 https://example.comreturn fetchData(https://another.com) // 返回另一个 Promise}).then((anotherData) {console.log(anotherData) // 输出数据来自 https://another.com}).catch((error) {console.error(捕获到错误, error) // 如果有 Promise 被拒绝则执行这里}).finally(() {console.log(所有操作完成无论成功还是失败) // 无论成功还是失败都会执行}) Promise的静态方法
Promise 提供了几个静态方法这些方法不是用于创建新的 Promise 实例的而是用于处理 Promise 对象的集合或进行某些特定的操作只能由构造函数调用。
1.resolve()方法
静态方法 Promise.resolve(value) 将异步执行的结果value作为参数返回一个以给定值解析后的已完成状态的 Promise 对象。 Promise.resolve(成功了).then((value) {console.log(value) // 输出: 成功了})// 如果传入的是 Promise 对象则直接返回该 Promise 对象let promise new Promise((resolve) resolve(直接返回的 Promise))Promise.resolve(promise).then((value) {console.log(value) // 输出: 直接返回的 Promise})
2.reject()方法
静态方法 Promise.reject(reason) 返回一个以特定原因reason拒绝状态的 Promise 对象。
Promise.reject(出错了).catch((error) {console.log(error) // 输出: 出错了
}) 3.all()方法
静态方法 Promise.all( iterator ) 用于处理一个 Promise 对象的数组或可迭代对象并返回一个新的 Promise 实例。这个新的 Promise 实例会在所有给定的 Promise 都成功完成时才会成功完成其结果是一个数组包含了所有给定 Promise 的结果按相同的顺序。
function delay(time, value) {return new Promise((resolve) setTimeout(() resolve(value), time))
}
Promise.race([delay(1000, 1s),delay(2000, 2s),delay(3000, 3s)
]).then((results) {console.log(results) // 输出: [1s, 2s, 3s]
})
4.race()方法
静态方法 Promise.race( iterator ) 同样接收一个 Promise 对象的数组或可迭代对象但它返回的新 Promise 实例会在给定的 Promise 数组中任何一个 Promise 改变状态无论是成功还是失败时立即以那个 Promise 的结果作为自己的结果来改变状态。
function delay(time, value) {return new Promise((resolve) setTimeout(() resolve(value), time))
}
Promise.race([delay(1000, 1s),delay(2000, 2s),delay(3000, 3s)
]).then((results) {console.log(results) // 输出: 1s因为第一个 delay(1000) 最快完成
})
5.allSettled() 方法
静态方法 Promise.allSettled(iterable)(ES2020 新增) 返回一个在所有给定的 Promise 都已经 settled完成无论结果如何后完成的 Promise 实例结果是一个数组数组中的每个元素都是一个对象表示对应的 Promise 的结果。
Promise.allSettled([Promise.resolve(3),Promise.reject(-1),Promise.resolve(5),Promise.reject(4)
]).then((results) {console.log(results)
})
/* 输出:
[ { status: fulfilled, value: 3 }, { status: rejected, reason: -1 }, { status: fulfilled, value: 5 }, { status: rejected, reason: 4 },
]
*/ Promise的实例方法
Promise 的实例方法主要包括 .then(), .catch(), 和 .finally()。这些方法允许你以链式调用的方式处理 Promise 的结果或错误。
1.then() 方法 1.then(onFulfilled , onRejected)
onFulfilled 指定resolve时调用的函数它接收 Promise 的值作为参数(一般由resolve传递)onRejected( 可选 )指定reject时调用的函数它接收 Promise 的拒绝原因作为参数(一般由reject传递) 2.then() 方法主要用于处理 Promise 成功的情况但也允许提供可选第二个参数 onRejected 函数来处理其失败的情况 3.then() 返回一个新的 Promise 实例对象
let promise new Promise((resolve, reject) {setTimeout(() reject(出错了), 1000)
})
promise.then((value) console.log(value), // 不会被调用因为 Promise 被拒绝了(reason) console.log(reason) // 会被调用并输出: 出错了
)
2.catch() 方法 1.catch(onRejected)方法是 .then(null, onRejected) 的语法糖
onRejected指定reject时调用的函数它接收 Promise 的拒绝原因作为参数(一般reject传递) 2catch() 主要用于处理 Promise 拒绝rejected的情况 3.catch() 也返回一个新的 Promise 实例对象
let promise new Promise((resolve, reject) {setTimeout(() reject(出错了), 1000)
})
promise.catch((error) {console.log(error) // 输出: 出错了// 可以选择在这里解决这个 Promise返回一个值或者另一个 Promise// return 错误已处理;
}) 4.不过它还有另外一个作用在执行 resolve 的回调也就是上面 then 中的第一个参 数时如果抛出异常了代码出错了那么并不会报错卡死 js而是会进到这个 catch 方法中。
let promise new Promise((resolve, reject) {setTimeout(() reject(失败), 1000)
}).then((value) {console.log(value)return 继续处理}).catch((error) {console.log(error) //输出失败}) 控制台结果 let promise new Promise((resolve, reject) {setTimeout(() reject(失败), 1000)
}).then((value) {console.log(value)return 继续处理}) 控制台结果 catch 既能处理 reject 回调也能捕捉错误 3.finally() 方法 .finally(onFinally) onFinally 当 Promise 结束时调用的函数它不接收任何参数也不关心 Promise 的结果。在 Promise 结束时无论它是成功还是失败都会回调执行。这为在 Promise 链的末尾执行清理操作提供了一种方式无论 Promise 的结果如何finally() 也返回一个新的 Promise 实例对象
let promise new Promise((resolve, reject) {setTimeout(() resolve(成功), 1000)// 或者 setTimeout(() reject(失败), 1000);
})
promise.then((value) {console.log(value) // 如果 Promise 成功则输出 成功return 继续处理 // 可以返回一个新的值或另一个 Promise}).catch((error) {console.error(error) // 如果 Promise 失败则输出错误信息}).finally(() {console.log(Promise 结束了无论成功还是失败)}) async/await
基本概念
Promise 虽然摆脱了回调地狱但 then 链式调⽤的阅读负担还是存在的为了优代码的阅读体验增强了代码的可读性和可维护性一种新的异步编程解决方案async/await诞生了。
async/await 是 JavaScript中用于处理异步操作的关键字对。它们使得异步代码看起来和写起来更像是同步代码从而大大增强了代码的可读性和可维护性。这对关键字特别适用于处理如文件读写、网络请求等耗时的异步操作。 基本用法
async
async关键字用于声明异步函数。这意味着该函数内部可以进行异步操作比如发送网络请求、读取文件等。异步函数内部可以使用 await 关键字来等待异步操作的完成。异步函数会隐式地返回一个 Promise 对象。如果函数执行成功并且显式地返回了一个值那么这个值会被封装成一个解析状态fulfilled的 Promise 对象。如果没有显式地返回任何值或者返回了一个非 Promise 类型的值JS会自动将这个值封成 Promise.resolve(value)其中 value 是函数的返回值或 undefined并返回这个 Promise 对象。 async function fun() {return async函数显示返回的值
}
console.log(fun()) 如果异步函数在执行过程中抛出了异常那么这个异常会被捕获并导致返回的 Promise 对象进入拒绝rejected状态异常信息作为拒绝的原因。
await
await 关键字只能在 async 函数内部使用。它用于等待一个 Promise 完成。使用 await 时async 函数的执行会暂停直到等待的 Promise 被解析fulfilled或拒绝rejected。如果 Promise 被解析await 表达式的结果就是 Promise 解析的值。此时async 函数的执行会继续进行。如果 Promise 被拒绝await 表达式会抛出一个异常。这个异常可以被 async 函数内部的 try...catch 语句捕获也可以继续向上传播直到被更高层级的错误处理机制捕获。
使用示例
假设我们有一个异步函数 fetchData它返回一个 Promise该 Promise 在一段时间后解析为一些数据
function fetchData() {return new Promise((resolve, reject) {setTimeout(() {resolve(数据加载完成)}, 1000)})
}使用 async/await 来调用这个函数
async function loadData() {try {const data await fetchData()console.log(data) // 输出: 数据加载完成} catch (error) {console.error(数据加载失败:, error)//throw error; // 可选重新抛出错误以便上层调用者可以处理 }
}
loadData()
在这个例子中loadData 是一个 async 函数它内部使用了 await 来等待 fetchData 函数返回的 Promise 完成。当 Promise 被解析时await 表达式的结果即 数据加载完成被赋值给 data 变量。如果 fetchData 函数抛出了一个错误虽然在这个例子中没有那么错误会被 catch 块捕获。
注意
await 只能在 async 函数内部使用。await 会暂停 async 函数内部后续代码的执行直到 await 后的 Promise 完成。await 可以用在任何返回 Promise 的表达式上不仅仅是函数调用。使用 async/await 可以使异步代码看起来更加直观和易于理解但也要注意不要滥用特别是在处理大量并发异步操作时。
async/await 的优势 代码清晰async/await 使得异步代码看起来和写起来更像是同步代码提高了代码的可读性和可维护性。 错误处理使用 try...catch 可以很容易地捕获和处理 await 表达式抛出的异常这与同步代码中的错误处理非常相似。 条件语句和循环在 async 函数中可以像处理同步代码一样使用 if 语句、for 循环等控制流语句来等待 Promise 完成。 中间件和组合虽然 async/await 本身并不提供新的组合或中间件模式但它与 Promises 很好地结合使得可以轻松地组合多个异步操作。 ---------------------------------------------------------------------------------------------------------------------------------
若有错误或描述不当的地方烦请评论或私信指正万分感谢