Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $YECBGYFECGEAFWHA as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2

Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $BBWFDDBHHYHDXXAB as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2
详细介绍JavaScript中Promise的基本概念及使用方法_创想鸟

详细介绍JavaScript中Promise的基本概念及使用方法

本篇文章给大家带来了关于javascript的相关知识,其中主要整理了promise的基本概念及使用方法的相关问题,包括了promise基本概念、使用promise解决回调地狱等等内容,下面一起来看一下,希望对大家有帮助。

详细介绍JavaScript中Promise的基本概念及使用方法

【相关推荐:javascript视频教程、web前端】

一、前言

异步是为了提高CPU的占用率,让其始终处于忙碌状态。

有些操作(最典型的就是I/O)本身不需要CPU参与,而且非常耗时,如果不使用异步就会形成阻塞状态,CPU空转,页面卡死。

立即学习“Java免费学习笔记(深入)”;

在异步环境下发生I/O操作,CPU就把I/O工作扔一边(此时I/O由其他控制器接手,仍然在数据传输),然后处理下一个任务,等I/O操作完成后通知CPU(回调就是一种通知方式)回来干活。

《JavaScript异步与回调》想要表达的核心内容是,异步工作的具体结束时间是不确定的,为了准确的在异步工作完成后进行后继的处理,就需要向异步函数中传入一个回调,从而在完成工作后继续下面的任务。

虽然回调可以非常简单的实现异步,但是却会由于多重嵌套形成回调地狱。避免回调地狱就需要解嵌套,将嵌套编程改为线性编程。

Promise是JavaScript中处理回调地狱最优解法。

二、Promise基本概念

Promise可以翻译为“承诺”,我们可以通过把异步工作封装称一个Promise,也就是做出一个承诺,承诺在异步工作结束后给出明确的信号!

Promise语法:

let promise = new Promise(function(resolve,reject){    // 异步工作})

通过以上语法,我们就可以把异步工作封装成一个Promise。在创建Promise时传入的函数就是处理异步工作的方法,又被称为executor(执行者)。

resolve和reject是由JavaScript自身提供的回调函数,当executor执行完了任务就可以调用:

resolve(result)——如果成功完成,并返回结果result;reject(error)——如果执行是失败并产生error;

executor会在Promise创建完成后立即自动执行,其执行状态会改变Promise内部属性的状态:

state——最初是pending,然后在resolve被调用后转为fulfilled,或者在reject被调用时变为rejected;result——最初时undefined,然后在resolve(value)被调用后变为value,或者在reject被调用后变为error;

2.1 异步工作的封装

文件模块的fs.readFile就是一个异步函数,我们可以通过在executor中执行文件读取操作,从而实现对异步工作的封装。

以下代码封装了fs.readFile函数,并使用resolve(data)处理成功结果,使用reject(err)处理失败的结果。

代码如下:

let promise = new Promise((resolve, reject) => {    fs.readFile('1.txt', (err, data) => {        console.log('读取1.txt')        if (err) reject(err)        resolve(data)    })})

如果我们执行这段代码,就会输出“读取1.txt”字样,证明在创建Promise后立刻就执行了文件读取操作。

Promise内部封装的通常都是异步代码,但是并不是只能封装异步代码。

2.2 Promise执行结果获取

以上Promise案例封装了读取文件操作,当完成创建后就会立即读取文件。如果想要获取Promise执行的结果,就需要使用then、catch和finally三个方法。

then

Promise的then方法可以用来处理Promise执行完成后的工作,它接收两个回调参数,语法如下:

promise.then(function(result),function(error))

第一个回调函数用于处理成功执行后的结果,参数result就是resolve接收的值;第二个回调函数用于处理失败执行后的结果,参数error就是reject接收的参数;

举例:

let promise = new Promise((resolve, reject) => {    fs.readFile('1.txt', (err, data) => {        console.log('读取1.txt')        if (err) reject(err)        resolve(data)    })})promise.then(    (data) => {        console.log('成功执行,结果是' + data.toString())    },    (err) => {        console.log('执行失败,错误是' + err.message)    })

如果文件读取成功执行,会调用第一个函数:

PS E:CodeNodedemos3-callback> node .index.js读取1.txt成功执行,结果是1

删掉1.txt,执行失败,就会调用第二个函数:

PS E:CodeNodedemos3-callback> node .index.js读取1.txt执行失败,错误是ENOENT: no such file or directory, open 'E:CodeNodedemos3-callback1.txt'

如果我们只关注成功执行的结果,可以只传入一个回调函数:

promise.then((data)=>{    console.log('成功执行,结果是' + data.toString())})

到这里我们就是实现了一次文件的异步读取操作。

闪念贝壳 闪念贝壳

闪念贝壳是一款AI 驱动的智能语音笔记,随时随地用语音记录你的每一个想法。

闪念贝壳 53 查看详情 闪念贝壳

catch

如果我们只关注失败的结果,可以把第一个then的回调传null:promise.then(null,(err)=>{...})。

亦或者采用更优雅的方式:promise.catch((err)=>{...})

let promise = new Promise((resolve, reject) => {    fs.readFile('1.txt', (err, data) => {        console.log('读取1.txt')        if (err) reject(err)        resolve(data)    })})promise.catch((err)=>{    console.log(err.message)})

.catch((err)=>{...})和then(null,(err)=>{...})作用完全相同。

finally

.finally是promise不论结果如何都会执行的函数,和try...catch...语法中的finally用途一样,都可以处理和结果无关的操作。

例如:

new Promise((resolve,reject)=>{    //something...}).finally(()=>{console.log('不论结果都要执行')}).then(result=>{...}, err=>{...})

finally回调没有参数,不论成功与否都会执行finally会传递promise的结果,所以在finally后仍然可以.then

三、使用Promise解决回调地狱

3.1 回调地狱出现的场景

现在,我们有一个需求:使用fs.readFile()方法顺序读取10个文件,并把十个文件的内容顺序输出。

由于fs.readFile()本身是异步的,我们必须使用回调嵌套的方式,代码如下:

fs.readFile('1.txt', (err, data) => {    console.log(data.toString()) //1    fs.readFile('2.txt', (err, data) => {        console.log(data.toString())        fs.readFile('3.txt', (err, data) => {            console.log(data.toString())            fs.readFile('4.txt', (err, data) => {                console.log(data.toString())                fs.readFile('5.txt', (err, data) => {                    console.log(data.toString())                    fs.readFile('6.txt', (err, data) => {                        console.log(data.toString())                        fs.readFile('7.txt', (err, data) => {                            console.log(data.toString())                            fs.readFile('8.txt', (err, data) => {                                console.log(data.toString())                                fs.readFile('9.txt', (err, data) => {                                    console.log(data.toString())                                    fs.readFile('10.txt', (err, data) => {                                        console.log(data.toString())                                        // ==> 地狱之门                                    })                                })                            })                        })                    })                })            })        })    })})

虽然以上代码能够完成任务,但是随着调用嵌套的增加,代码层次变得更深,维护难度也随之增加,尤其是我们使用的是可能包含了很多循环和条件语句的真实代码,而不是例子中简单的 console.log(...)。

3.2 不使用回调产生的后果

如果我们不使用回调,直接把fs.readFile()顺序的按照如下代码调用一遍,会发生什么呢?

//注意:这是错误的写法fs.readFile('1.txt', (err, data) => {    console.log(data.toString())})fs.readFile('2.txt', (err, data) => {    console.log(data.toString())})fs.readFile('3.txt', (err, data) => {    console.log(data.toString())})fs.readFile('4.txt', (err, data) => {    console.log(data.toString())})fs.readFile('5.txt', (err, data) => {    console.log(data.toString())})fs.readFile('6.txt', (err, data) => {    console.log(data.toString())})fs.readFile('7.txt', (err, data) => {    console.log(data.toString())})fs.readFile('8.txt', (err, data) => {    console.log(data.toString())})fs.readFile('9.txt', (err, data) => {    console.log(data.toString())})fs.readFile('10.txt', (err, data) => {    console.log(data.toString())})

以下是我测试的结果(每次执行的结果都是不一样的):

PS E:CodeNodedemos3-callback> node .index.js12346957108

产生这种非顺序结果的原因是异步,并非多线程并行,异步在单线程里就可以实现。

之所以在这里使用这个错误的案例,是为了强调异步的概念,如果不理解为什么会产生这种结果,一定要回头补课了!

3.3 Promise解决方案

使用Promise解决异步顺序文件读取的思路:

封装一个文件读取promise1,并使用resolve返回结果使用promise1.then接收并输出文件读取结果在promise1.then中创建一个新的promise2对象,并返回调用新的promise2.then接收并输出读取结果在promise2.then中创建一个新的promise3对象,并返回调用新的promise3.then接收并输出读取结果…

代码如下:

let promise1 = new Promise((resolve, reject) => {    fs.readFile('1.txt', (err, data) => {        if (err) reject(err)        resolve(data)    })})let promise2 = promise1.then(    data => {        console.log(data.toString())        return new Promise((resolve, reject) => {            fs.readFile('2.txt', (err, data) => {                if (err) reject(err)                resolve(data)            })        })    })let promise3 = promise2.then(    data => {        console.log(data.toString())        return new Promise((resolve, reject) => {            fs.readFile('3.txt', (err, data) => {                if (err) reject(err)                resolve(data)            })        })    })let promise4 = promise3.then(    data => {        console.log(data.toString())        //.....    })... ...

这样我们就把原本嵌套的回调地狱写成了线性模式。

但是代码还存在一个问题,虽然代码从管理上变的美丽了,但是大大增加了代码的长度。

3.4 链式编程

以上代码过于冗长,我们可以通过两个步骤,降低代码量:

封装功能重复的代码,完成文件读取和输出工作省略中间promise的变量创建,将.then链接起来

代码如下:

function myReadFile(path) {    return new Promise((resolve, reject) => {        fs.readFile(path, (err, data) => {            if (err) reject(err)            console.log(data.toString())            resolve()        })    })}myReadFile('1.txt')    .then(data => { return myReadFile('2.txt') })    .then(data => { return myReadFile('3.txt') })    .then(data => { return myReadFile('4.txt') })    .then(data => { return myReadFile('5.txt') })    .then(data => { return myReadFile('6.txt') })    .then(data => { return myReadFile('7.txt') })    .then(data => { return myReadFile('8.txt') })    .then(data => { return myReadFile('9.txt') })    .then(data => { return myReadFile('10.txt') })

由于myReadFile方法会返回一个新的Promise,我们可以直接执行.then方法,这种编程方式被称为链式编程。

代码执行结果如下:

PS E:CodeNodedemos3-callback> node .index.js12345678910

这样就完成了异步且顺序的文件读取操作。

注意:在每一步的.then方法中都必须返回一个新的Promise对象,否则接收到的将是上一个旧的Promise。

这是因为每个then方法都会把它的Promise继续向下传递。

【相关推荐:javascript视频教程、web前端】

以上就是详细介绍JavaScript中Promise的基本概念及使用方法的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/549318.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
人体姿态估计:基于飞桨复现Hourglass
上一篇 2025年11月9日 19:17:40
8200mAh双灭霸手机!vivo Y500图赏
下一篇 2025年11月9日 19:17:46

相关推荐

  • 360浏览器怎么禁止网页自动刷新_360浏览器阻止页面定时刷新设置方法

    1、通过360浏览器开发者工具删除含http-equiv=”refresh”的meta标签可临时阻止刷新;2、启用弹窗拦截功能可屏蔽由脚本触发的自动刷新;3、使用无痕模式浏览可限制脚本运行,避免页面刷新;4、安装“Tampermonkey”等扩展并添加屏蔽规则可实现长期有效阻…

    2026年9月22日
    400
  • UC浏览器为什么无法登录某些网站账号_UC浏览器部分网站无法登录原因及对策

    首先关闭广告过滤功能,清除缓存与Cookie,关闭云端加速,切换网络或DNS,最后尝试桌面模式或其他浏览器解决UC浏览器登录无响应问题。 如果您尝试在UC浏览器中登录某个网站账号,但页面无响应或提示错误,则可能是由于浏览器的安全策略、缓存问题或设置限制导致无法正常加载登录界面。以下是解决此问题的步骤…

    2026年9月22日
    200
  • 解决PHP应用中本地文件更新后网页视图不刷新的缓存问题

    本文探讨了PHP应用中,本地JSON或图片文件更新后,网页视图无法实时刷新的常见问题。核心原因在于浏览器缓存机制。文章将提供多种解决方案,包括强制刷新、隐身模式诊断、以及通过URL参数、服务器配置(.htaccess)和文件版本控制来有效管理缓存,确保用户始终获取最新数据。 理解问题:本地文件更新与…

    2026年9月22日
    200
  • Bun 1.3 正式发布

    2025年10月10日,高性能 javascript 运行时 bun 发布了 1.3 版本。这是 bun 项目迄今为止最重大的版本更新,标志着 bun 从单纯的运行时工具演变为一个功能完备的全栈 javascript 开发平台。 从运行时到全栈平台的跨越 Bun 1.3 的核心突破在于将前端开发能力…

    2026年9月21日
    100
  • safari浏览器如何设置链接在新窗口而不是新标签页打开_safari浏览器链接新窗口打开设置

    通过快捷键或第三方扩展可实现Safari中链接在新窗口打开:1. 按住Command键点击链接可临时在新窗口打开;2. 使用AppleScript脚本通过“自动操作”创建快速操作以新建Safari窗口;3. 网站自身代码如window.open()会强制新窗口打开;4. 安装可信扩展如“Link i…

    2026年9月21日
    100
  • VSCode语言特性贡献点配置

    通过配置package.json中的contributes字段可实现VSCode语言扩展,依次需设置语法高亮(grammars)、语言绑定(languages)、激活事件(activationEvents)及语言服务器功能(如补全、跳转),并定义language-configuration.json…

    2026年9月21日
    100
  • 使用本地HTML文件运行JavaScript脚本失败的原因及解决方案

    本文旨在帮助开发者理解在没有Web服务器的情况下,直接通过浏览器打开本地HTML文件时,JavaScript脚本可能无法正常运行的原因,并提供相应的解决方案。文章将深入探讨浏览器安全策略、相对路径问题以及如何正确引入和执行JavaScript脚本,确保你的HTML、CSS和JavaScript代码能…

    2026年9月21日
    100
  • 悟空浏览器开发者工具的控制台怎么用_悟空浏览器Console控制台使用入门教程

    首先启用悟空浏览器开发者工具并进入Console标签,可查看错误、警告等日志信息,通过过滤功能定位问题;支持执行JavaScript代码实时调试,监控网络请求失败及全局异常,还可清空或保存日志以便分析。 如果您在使用悟空浏览器进行网页开发或调试时,发现页面元素未按预期工作或脚本报错,则可以借助开发者…

    2026年9月21日
    800
  • 实现搜索结果的 A-Z 排序:PHP 教程

    本文档旨在指导开发者如何在 PHP 中实现搜索结果的 A-Z 排序功能。通过结合 AJAX 技术和 PHP 函数,可以方便地对通过 POST 方法获取的医生搜索结果进行 A-Z 排序,从而优化用户浏览体验。本文将详细介绍实现步骤,提供可复用的代码示例,并着重强调注意事项,旨在帮助开发者快速掌握并应用…

    2026年9月21日
    200
  • PHP错误日志怎么查看_PHP错误日志定位与查看方法

    要查看PHP错误日志,首先确定php.ini中error_log路径,若未设置则检查Web服务器(如Apache/Nginx)错误日志;确保log_errors=On、error_reporting合理配置,并通过tail、grep等工具分析日志,结合框架日志和系统日志(如syslog)全面定位问题…

    2026年9月21日
    300
  • 谷歌浏览器官方在线访问 最新版Chrome官网登录

    谷歌浏览器官方在线访问入口是https://www.google.cn/chrome/,提供简洁界面、跨设备同步、高效内核、安全防护和丰富扩展生态。 谷歌浏览器官方在线访问入口在哪里?这是不少网友都关注的,接下来由PHP小编为大家带来最新版Chrome官网登录地址,想要获取纯净浏览体验的网友一起随小…

    2026年9月21日
    200
  • JavaScript中的模块联邦如何实现微前端的代码共享?

    模块联邦通过运行时动态加载实现微前端代码共享,无需打包公共依赖。使用 ModuleFederationPlugin 配置 name、remotes、exposes 和 shared,使应用可暴露或引入远程模块,支持组件、工具函数及状态管理共享,提升复用性并减少冗余。 模块联邦通过在构建时让不同应用直…

    2026年9月21日
    200
  • UC浏览器网页上的文字无法选中复制怎么办 UC浏览器解决网页文字禁止复制问题

    答案:可通过开发者工具、阅读模式、打印预览、OCR识别或自定义脚本解除UC浏览器网页复制限制。具体操作依次为:开启开发者工具并执行JavaScript代码解除限制;启用阅读模式净化页面内容;使用打印预览重新渲染页面以选中文字;对截图应用OCR技术提取文本;添加书签脚本自动移除禁用选择的代码,从而实现…

    2026年9月21日
    100
  • JavaScript中的尾调用优化(TCO)在ES6中如何工作?

    尾调用是指函数的最后一个动作调用另一个函数,ES6引入尾调用优化以重用栈帧、避免内存溢出,支持真正的尾递归,如阶乘函数通过累积参数实现。 尾调用优化(Tail Call Optimization, TCO)是ES6引入的一项语言特性,目的是在特定条件下重用函数调用栈帧,避免不必要的内存增长,从而支持…

    2026年9月21日
    200
  • JSF应用中Markdown文档动态链接处理指南

    本教程旨在解决jsf web应用程序中集成markdown文档时,如何动态处理内部链接以实现页面局部更新的问题。通过结合服务器端markdown渲染和客户端javascript事件监听,我们可以拦截markdown生成的html链接点击事件,利用ajax异步加载并渲染目标markdown文件,从而在…

    2026年9月21日
    600
  • 如何自定义代码的格式化规则?

    自定义代码格式化规则需选择合适工具并配置文件实现统一风格。1. 根据语言选用主流工具如Prettier、Black、clang-format等;2. 在项目根目录创建对应配置文件如.prettierrc、.eslintrc.js或pyproject.toml,定义缩进、引号、行宽等规则;3. 将配置…

    2026年9月21日
    100
  • 怎样在VSCode中快速生成注释文档?

    安装插件如Document This和Koro File Header,通过快捷键在VSCode中快速生成函数及文件注释,支持自定义模板,提升注释效率与规范性。 在 VSCode 中快速生成注释文档,主要依赖插件和快捷键配合代码语言特性来实现。不同编程语言支持方式略有差异,但核心思路是使用智能提示和…

    2026年9月21日
    200
  • 如何为特定语言配置VSCode的语法高亮?

    安装对应语言扩展并关联文件类型,可实现VSCode语法高亮。首先通过扩展面板安装目标语言插件,如Ruby或Rust;若文件扩展名未被识别,需手动将扩展名关联至正确语言;最后可在settings.json中配置editor.tokenColorCustomizations来自定义高亮颜色,确保语法解析…

    2026年9月21日
    100
  • 为什么VSCode的语法高亮有时会失效?

    语法高亮失效通常由语言模式识别错误、扩展冲突或配置问题导致。1. 检查右下角语言模式并手动切换为正确类型,确保文件有正确扩展名;2. 禁用近期安装的扩展或以 code –disable-extensions 启动排查冲突;3. 切换至默认主题并检查 settings.json 是否覆盖颜…

    2026年9月21日
    600
  • VSCode的括号着色功能如何帮助你避免语法错误?

    VSCode括号着色功能通过彩色高亮匹配括号,帮助用户直观识别嵌套结构、提升代码可读性,并快速发现遗漏或多余括号,减少语法错误。 VSCode的括号着色功能通过视觉方式帮你快速识别代码中的匹配和嵌套结构,减少语法错误的发生。当你在编写代码时,成对出现的括号(如()、[]、{})会被高亮显示为相同或相…

    2026年9月21日
    000

发表回复

登录后才能评论
关注微信