promise异步编程指南
promise 是什么
Promise 是异步编程的一种解决方案,可以替代传统的解决方案–回调函数和事件。ES6 统一了用法,并原生提供了 Promise 对象。作为对象,Promise 有以下两个特点:
(1)对象的状态不受外界影响。
(2)一旦状态改变了就不会再变,也就是说任何时候 Promise 都只有一种状态。
Promise 有三种状态,分别是 Pending (进行中)、Resolved (已完成)、Rejected (已失败)。Promise 从 Pending 状态开始,如果成功就转到成功态,并执行 resolve 回调函数;如果失败就转到失败状态并执行 reject 回调函数。
可以通过 Promise 的构造函数创建 Promise 对象
var promise = new Promise((resolve,reject) => {setTimeout(()=>{console.log("hello world")
}, 2000)
})
Promise 构造函数接受一个函数作为参数,该函数的两个参数是 resolve ,reject,它们由 JavaScript 引擎提供。其中 resolve 函数的作用是当 Promise 对象转移到成功,调用 resolve 并将操作结果作为其参数传递出去;reject 函数的作用是当 Promise 对象的状态变为失败时,将操作报出的错误作为参数传递出去。如下代码:
function greet(){var promise = new Promise(function(resolve,reject){var greet = "hello world"resolve(greet)
})return promise
}
greet().then(v=>{console.log(v)//*
})
Promise 的 then 方法,promise 的 then 方法带有一下三个参数:成功的回调,失败的回调,前进的回调。一般情况下只需要实现第一个,后面的是可选的。Promise 中最为重要的状态,通过 then 的状态传递可以实现的回调函数链式操作的实现。先执行以下代码:
function greet () {var promise = new Promise (function(resolve, reject){var greet = "hello world"resolve(greet)})return promise
}
var p = greet().then(v => {console.log(v) // Promise { <pending> }
})
console.log(p) // hello world
catch 用法
function judgeNumber(num){var promise1 = new Promise(function(resolve,reject){num =5;if(num<5){resolve("num小于5,值为:"+num);}else{reject("num不小于5,值为:"+num);}});return promise1;
}judgeNumber().then(function(message){console.log(message);}
)
.catch(function(message){console.log(message);
})
Promise 的 all 方法提供了并行执行异步操作的能力,在 all 中所有异步操作结束后才执行回调。
function p1(){var promise1 = new Promise(function(resolve,reject){console.log("p1的第一条输出语句");console.log("p1的第二条输出语句");resolve("p1完成");})return promise1;
}function p2(){var promise2 = new Promise(function(resolve,reject){console.log("p2的第一条输出语句");setTimeout(()=>{console.log("p2的第二条输出语句");resolve("p2完成")},2000);})return promise2;
}function p3(){var promise3 = new Promise(function(resolve,reject){console.log("p3的第一条输出语句");console.log("p3的第二条输出语句");resolve("p3完成")});return promise3;
}Promise.all([p1(),p2(),p3()]).then(function(data){console.log(data);
})p1的第一条输出语句
p1的第二条输出语句
p2的第一条输出语句
p3的第一条输出语句
p3的第二条输出语句
p2的第二条输出语句
['p1完成', 'p2完成', 'p3完成']
在 all 中的回调函数中,等到所有的 Promise 都执行完,再来执行回调函数,race 则不同它等到第一个 Promise 改变状态就开始执行回调函数。将上面的all改为race,得到
Promise.race([p1(),p2(),p3()]).then(function(data){console.log(data);
})
如何实现一个 promise
(function(window,undefined){// resolve 和 reject 最终都会调用该函数
var final = function(status,value){var promise = this, fn, st;if(promise._status !== 'PENDING') return;// 所以的执行都是异步调用,保证then是先执行的setTimeout(function(){promise._status = status;st = promise._status === 'FULFILLED'queue = promise[st ? '_resolves' : '_rejects'];while(fn = queue.shift()) {value = fn.call(promise, value) || value;}promise[st ? '_value' : '_reason'] = value;promise['_resolves'] = promise['_rejects'] = undefined;});
}//参数是一个函数,内部提供两个函数作为该函数的参数,分别是resolve 和 reject
var Promise = function(resolver){if (!(typeof resolver === 'function' ))throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');//如果不是promise实例,就new一个if(!(this instanceof Promise)) return new Promise(resolver);var promise = this;promise._value;promise._reason;promise._status = 'PENDING';//存储状态promise._resolves = [];promise._rejects = [];//var resolve = function(value) {//由於apply參數是數組final.apply(promise,['FULFILLED'].concat([value]));}var reject = function(reason){final.apply(promise,['REJECTED'].concat([reason]));}resolver(resolve,reject);
}Promise.prototype.then = function(onFulfilled,onRejected){var promise = this;// 每次返回一个promise,保证是可thenable的return new Promise(function(resolve,reject){function handle(value) {// 這一步很關鍵,只有這樣才可以將值傳遞給下一個resolvevar ret = typeof onFulfilled === 'function' && onFulfilled(value) || value;//判断是不是promise 对象if (ret && typeof ret ['then'] == 'function') {ret.then(function(value) {resolve(value);}, function(reason) {reject(reason);});} else {resolve(ret);}}function errback(reason){reason = typeof onRejected === 'function' && onRejected(reason) || reason;reject(reason);}if(promise._status === 'PENDING'){promise._resolves.push(handle);promise._rejects.push(errback);}else if(promise._status === FULFILLED){ // 状态改变后的then操作,立刻执行callback(promise._value);}else if(promise._status === REJECTED){errback(promise._reason);}});
}Promise.prototype.catch = function(onRejected){return this.then(undefined, onRejected)
}Promise.prototype.delay = function(ms,value){return this.then(function(ori){return Promise.delay(ms,value || ori);})
}Promise.delay = function(ms,value){return new Promise(function(resolve,reject){setTimeout(function(){resolve(value);console.log('1');},ms);})
}Promise.resolve = function(arg){return new Promise(function(resolve,reject){resolve(arg)})
}Promise.reject = function(arg){return Promise(function(resolve,reject){reject(arg)})
}Promise.all = function(promises){if (!Array.isArray(promises)) {throw new TypeError('You must pass an array to all.');}return Promise(function(resolve,reject){var i = 0,result = [],len = promises.length,count = len//这里与race中的函数相比,多了一层嵌套,要传入indexfunction resolver(index) {return function(value) {resolveAll(index, value);};}function rejecter(reason){reject(reason);}function resolveAll(index,value){result[index] = value;if( --count == 0){resolve(result)}}for (; i < len; i++) {promises[i].then(resolver(i),rejecter);}});
}Promise.race = function(promises){if (!Array.isArray(promises)) {throw new TypeError('You must pass an array to race.');}return Promise(function(resolve,reject){var i = 0,len = promises.length;function resolver(value) {resolve(value);}function rejecter(reason){reject(reason);}for (; i < len; i++) {promises[i].then(resolver,rejecter);}});
}window.Promise = Promise;})(window);
async await
async 表示这是一个 async 函数, await 只能用在 async 函数里面,不能单独使用
async 返回的是一个 Promise 对象,await 就是等待这个 promise 的返回结果后,再继续执行
await 等待的是一个 Promise 对象,后面必须跟一个 Promise 对象,但是不必写 then(),直接就可以得到返回值
async/await 的优点
方便级联调用:即调用依次发生的场景;
同步代码编写方式:Promise 使用 then 函数进行链式调用,一直点点点,是一种从左向右的横向写法;async/await 从上到下,顺序执行,就像写同步代码一样,更符合代码编写习惯;
多个参数传递:Promise 的 then 函数只能传递一个参数,虽然可以通过包装成对象来传递多个参数,但是会导致传递冗余信息,频繁的解析又重新组合参数,比较麻烦;async/await 没有这个限制,可以当做普通的局部变量来处理,用 let 或者 const 定义的块级变量想怎么用就怎么用,想定义几个就定义几个,完全没有限制,也没有冗余工作;
同步代码和异步代码可以一起编写:使用 Promise 的时候最好将同步代码和异步代码放在不同的 then 节点中,这样结构更加清晰;async/await 整个书写习惯都是同步的,不需要纠结同步和异步的区别,当然,异步过程需要包装成一个 Promise 对象放在 await 关键字后面;
基于协程:Promise 是根据函数式编程的范式,对异步过程进行了一层封装,async/await 基于协程的机制,是真正的“保存上下文,控制权切换……控制权恢复,取回上下文”这种机制,是对异步过程更精确的一种描述;
async/await 是对 Promise 的优化:async/await 是基于 Promise 的,是进一步的一种优化,不过在写代码时,Promise 本身的 API 出现得很少,很接近同步代码的写法
相关文章:
promise异步编程指南
promise 是什么 Promise 是异步编程的一种解决方案,可以替代传统的解决方案–回调函数和事件。ES6 统一了用法,并原生提供了 Promise 对象。作为对象,Promise 有以下两个特点: (1)对象的状态不受外界影响。 (2)一旦状态改变了就不…...
20230411----重返学习-网易云音乐首页案例-git远程仓库
day-047-forty-seven-20230411-网易云音乐首页案例-git远程仓库 网易云音乐首页案例 事件委托 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><title>2.事件委托</title><style>.parent-box…...
Ansys Zemax | 模拟 AR 系统中的全息光波导:第二部分
AR 系统通常使用全息图将光耦合到波导中。本文展示了如何继续改进 本系列文章的第一部分 (点击查看)中建模的初步设计。(联系我们获取文章附件) 简介 AR 是一种允许屏幕上的虚拟世界与现实场景结合并交互的技术。 本文演示了如何…...
常用Git命令
整理了一些常用的git命令,备忘 查看仓库状态 git status查看提交记录 git log创建本地分支 git branch [branch name]创建远程分支 git push origin [branch name]查看本地分支 git branch -v查看远程分支 git branch -a切换分支 git checkout [branch name]查看远程…...
新手程序员被职场PUA的时候正确的化解姿势
新手程序员遇到了职场p u a 应该怎么办 最近我和有个粉丝聊天 他刚毕业进入了一家公司 就遭遇到了职场p u a 导致自己的自信心被打击 非常的痛苦 他是属于进入一家小公司 而这家公司的代码真的是非常的烂 他截图发了一段他目前 正在处理的代码给我 真的是太烂了 很多代码就是属…...
LINUX_kali学习笔记
基础命令 命令说明示例pwd查看当前路径ls查看当前文件夹下文件 .开头为隐藏文件 (文件夹下使用ctrlh查看)ls -a(查看文件及隐藏文件)ls -alh(查看文件及显示详情)cd切换目录cd /(切换到根目录&…...
第十天面试实战篇
目录 一、springboot的常用注解? 二、springmvc常用注解? 三、mysql的内连接和外连接有什么区别?比如有两张表:A和B内连接只返回两个表A和B的交集部分 四、redis分布式锁的缺点有哪些? 五、如何使用reddssion解决r…...
YML是一种数据存储格式
读取yml配置信息 Value("${province}") private String province; Value("${user.sname}") private String name1; Value("${user1[1].name}") private String name; Value("${server.port}") private int port; server:port: 8099 #…...
笔记:Java关于轻量级锁与重量级锁之间的问答
问题:如果在轻量级锁状态下出现锁竞争,不一定会直接升级为重量级锁,而是会先尝试自旋获取锁,那么有a b两个线程竞争锁,a成功获取锁了,b就一定失败,那么轻量级锁就一定升级为重量级锁,…...
有哪些通过PMP认证考试的心得值得分享?
回顾这100多天来艰辛的备考经历,感慨颇多 一,对于pmp的认知 百度百科:PMP(Project Management Professional)指项目管理专业人士(人事)资格认证。美国项目管理协会(PMI)举…...
【unity learn】【Ruby 2D】角色发射飞弹
前面制作了敌人的随机运动以及动画控制,接下来就是Ruby和Robot之间的对决了! 世界观背景下,小镇上的机器人出了故障,致使全镇陷入了危机,而Ruby肩负着拯救小镇的职责,于是她踏上了修复机器人的旅途。 之前…...
C++模板基础(九)
完美转发与 lambda 表达式模板 void f(int& input) {std::cout << "void f(int& input)\t" << input << \n; }void f(int&& input) {std::cout << "void f(int&& input)\t" << input << \n;…...
【剑指 Offer】(1)
文章目录前言一、 数组中重复的数字:fire: 解决方法:dog: 代码二、二维数组中的查找:fire:思路:dog:代码三、替换空格:fire:思路:dog: 代码四、从尾到头打印链表:fire:思路:dog:代码:dog: 代码五、重建二叉树:fire:思路:dog: 代码总结前言 剑指offer系列是一本非常著名的面试题…...
每日一题 leetcode1026 2023-4-18
1026. 节点与其祖先之间的最大差值 力扣题目链接 给定二叉树的根节点 root,找出存在于 不同 节点 A 和 B 之间的最大值 V,其中 V |A.val - B.val|,且 A 是 B 的祖先。 (如果 A 的任何子节点之一为 B,或者 A 的任何…...
【Python_Scrapy学习笔记(十二)】基于Scrapy框架实现POST请求爬虫
基于Scrapy框架实现POST请求爬虫 前言 本文中介绍 如何基于 Scrapy 框架实现 POST 请求爬虫,并以抓取指定城市的 KFC 门店信息为例进行展示 正文 1、Scrapy框架处理POST请求方法 Scrapy框架 提供了 FormRequest() 方法来发送 POST 请求; FormReques…...
《花雕学AI》02:人工智能挺麻利,十分钟就为我写了一篇长长的故事
ChatGPT最近火爆全网,上线短短两个多月,活跃用户就过亿了,刷新了历史最火应用记录,网上几乎每天也都是ChatGPT各种消息。国内用户由于无法直接访问ChatGPT,所以大部分用户都无缘体验。不过呢,前段时间微软正…...
做程序员累了想要转行?我想给大家分享一下看法
今天早上起床时,我看到有粉丝评论说关于程序员的话题,如果做着觉得累了,就会觉得自己不适合这个工作,想转行。我想给大家分享一下我的看法。 在我刚开始工作时,有人说我不适合做这个工作,但是我坚持了下来…...
如果你想从事人工智能职业,学习Python吧
人工智能并不会抢走你的工作,至少目前还不会。人工智能和机器学习(AI/ML)最好的应用是补充人类的创造力,而不是取代它。具有讽刺意味的是,最好的大型语言模型(LLMs)可能是通过使用受版权保护的人…...
百模大战,谁是下一个ChatGPT?
“不敢下手,现在中国还没跑出来一家绝对有优势的大模型,上层应用没法投,担心押错宝。”投资人Jucy(化名)向光锥智能表示,AI项目看得多、投的少是这段时间的VC常态。 ChatGPT点燃AI大爆炸2个月中࿰…...
Revit中怎么绘制多面坡度的屋顶及生成墙
一、Revit中怎么绘制多面坡度的屋顶 像这种坡屋顶我们可以观察到,它的屋顶轮廓都是带有坡度的,那我可以通过添加定义坡度的方式来绘制出该屋顶。 点击建筑选项卡中的屋顶按钮,选择迹线屋顶。 选择使用拾取线工具,在选项栏中将偏…...
深度解析ConcurrentHashMap设计演进:从分段锁到无锁化的并发之路
在Java并发编程领域,ConcurrentHashMap绝对是“并发容器扛鼎之作”——它既解决了HashMap并发环境下的数据不一致(死循环、数据丢失)问题,又突破了Hashtable全表锁的性能瓶颈,成为高并发场景下K-V存储的首选。自JDK1.5…...
实战指南:基于快马生成电商订单自动化n8n工作流,无缝衔接shopify与crm
实战指南:基于快马生成电商订单自动化n8n工作流,无缝衔接shopify与crm 最近在帮朋友优化他们电商业务的后台流程,发现手动处理订单实在太费时间了。特别是遇到大促期间,订单量暴增,人工操作不仅效率低还容易出错。于是…...
避坑指南:Virtio-PCI设备初始化失败的6个常见原因及解决方案
Virtio-PCI设备初始化故障深度排查手册 虚拟化技术在现代数据中心的应用已无处不在,而Virtio作为半虚拟化的事实标准协议,其PCI设备初始化过程却常常成为运维人员的"暗礁区"。上周处理某金融云平台故障时,我发现一个反复出现的现象…...
C语言回调函数在TCP客户端中的实现与应用
C语言回调函数在TCP客户端中的实现与应用1. 回调函数基础概念回调函数是一种通过函数指针实现的编程机制,允许将一个函数作为参数传递给另一个函数。在C语言中,回调函数的实现完全依赖于函数指针,这与C、Python等现代语言中可能使用仿函数或匿…...
【adb端口5555】烽火hg680系列安卓9线刷全攻略:告别强制升级与花屏困扰
1. 烽火HG680系列机顶盒的痛点与解决方案 最近在折腾烽火HG680-GY和HG680-GC这两款机顶盒的朋友应该都深有体会,官方系统用着用着就会弹出强制升级提示,有时候还会莫名其妙出现花屏问题。作为一个折腾过不下20台烽火盒子的老玩家,我太理解这种…...
终极指南:使用compressorjs实现专业级前端图片压缩与编辑功能
终极指南:使用compressorjs实现专业级前端图片压缩与编辑功能 【免费下载链接】compressorjs compressorjs: 是一个JavaScript图像压缩库,使用浏览器原生的canvas.toBlob API进行图像压缩。 项目地址: https://gitcode.com/gh_mirrors/co/compressorjs…...
便携式动物源性成分检测仪 肉类真假检测仪
整机采用极简一体化便携设计,无冗余复杂配件,整套系统由两大核心部分构成,兼顾设备专业性与便携实用性,开箱即可快速开展检测工作,无需额外搭建复杂检测环境,完美适配现场流动检测需求:核心检测…...
Python+Spark+Hadoop商品评论数据分析可视化系统+情感分析 大数据毕业设计
1、项目介绍 技术栈: Python语言、Django框架、MySQL数据库 、Echarts可视化、情感分析、HTML商品评论数据分析可视化系统是基于Python语言和Django框架开发的一个Web应用程序。它的主要功能是对商品评论数据进行分析,并将分析结果通过Echarts可视化库展…...
5步构建静音高效的电脑散热系统:FanControl全面指南
5步构建静音高效的电脑散热系统:FanControl全面指南 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_Trending/fa/F…...
TrafficMonitor插件系统终极指南:3步打造个性化系统监控中心
TrafficMonitor插件系统终极指南:3步打造个性化系统监控中心 【免费下载链接】TrafficMonitorPlugins 用于TrafficMonitor的插件 项目地址: https://gitcode.com/gh_mirrors/tr/TrafficMonitorPlugins TrafficMonitor插件系统是一款强大的扩展框架࿰…...
