Javascript基础之-Promise

转载自: http://www.lht.ren/article/3/

Promise是什么呢?根据ecma-262的定义:

Promise是一个被用于延时计算的最终结果的占位符

(A Promise is an object that is used as a placeholder for the eventual results of a deferred (and possibly asynchronous) computation.)

这个怎么理解呢

比如说,我要去麦当劳买点吃的,下单以后人家会先给你一个订单号,等人家外卖做好了,会提示你,并用那个订单小票来换取你真正的食物,在这时候,那个订单小票就是你这顿饭的占位符。

回到Promise,它有三种状态,分别为完成,拒绝和待决议,

而待决议的状态代表它还没有被完成或者是拒绝,也就是说,如果它一直都是处于待决议的状态,意味着代码永远都不会继续往下执行

所以下面这段代码永远都执行不到finish

new Promise((resolve, reject) => {console.log('waiting');document.writeln('waiting');
}).then((msg) => {console.log('finish');
});

也就是意味着,必须显示的执行resolve()或者是reject,程序才会继续往下执行。

那怎么解决这个问题呢,其实很简单,决议一下就好了嘛,哈哈~~

或者给Promise设置一个超时时间,看下面的代码:

function timeoutPromise(delay) {return new Promise( function(resolve,reject){setTimeout( function(){reject( "Timeout!" );}, delay );} );
}
Promise.race([new Promise(() => {console.log('waiting...');}),timeoutPromise(3000)
]).catch((msg) => {console.log(msg);
})

这段代码呢,会先等待5秒,然后会打印出一个错误"Timeout",在这里,Promise.race()实际上就是竞态的,谁先决议,其余的就会被抛弃。所以咱们三秒钟后决议一个拒绝,剩下那个promise自动被抛弃了

说到错误处理了,思考下面的代码:

new Promise((resolve, reject) => {foo.bar();
}).then((msg) => {console.log(msg);
}, null).then((msg) => {console.log(msg);
}, (err) => {console.log(err);
});

这段代码,很明显foo不是对象,所以会报ReferenceError,所以呢,会自动决议为reject,然后他紧接着的那个then没有拒绝处理回调,然后接着往下传递错误,直到有reject回调为止,假如一直都没有reject回调呢,他就会在全局抛出一个未捕获的异常。

那么如果在Promise决议多次呢,实际上只有第一次决议生效,也就是说,只能有一种决议生效,又成功又失败,或者成功多次,失败多次听着就不靠谱是吧,思考下面的代码

new Promise((resolve, reject) => {resolve();reject();console.log('exec finish');
}).then((msg) => {console.log('resolve');
}, (err) => {console.log('reject');
});

运行结果是输出exec finish 和resolve,因为第一次决议为resolve, 所以reject决议就被抛弃了

大家想一下,决议后对应的then里面的回调函数是同步还是异步的呢,思考下面这个问题:

console.log(0);
let p = new Promise((resolve, reject) => {console.log(1);resolve();console.log(2);
})
console.log(3);
p.then((msg) => {console.log(4);
});
console.log(5);

他的结果是 1 2 3 5 4

答案很显然啦,是异步的!实际上当决议以后,就会把它放到一个异步队列里调用

那为什么要这么设计呢,会给我们带来什么好处呢,思考下面这个问题

function getResult() {console.log(a);
}
function opt() {if (isAsync) {setTimeout(() => {getResult();}, 0);} else {getResult();}
}
var a = 0;
var isAsync = false;
opt();
a++;
isAsync = true;
opt();
a++;

他的结果输出的是0 2,那为什么不是0, 1,实际上就是因为由于同步和异步的的不确定性导致的,也叫zalgo,所以呢,要想消除他们的不确定性,必须就让他里面的代码要么都是同步,要么都是异步,这也是then为什么是异步的原因了

关于then,还有一个问题,就是then的返回值是什么,来继续看问题

var p = Promise.resolve( 21 );
var p2 = p.then( function(v){return v * 2;
});
console.log(p2);

通过他的结果,你很容易就能看出来,then的返回值是一个Promise,那么,这个then回调是不是可以这么理解呢?

function callback() {return Promise.resolve(42);
}

如果是的话,那么咱们就研究一下Promise.resolve()的特性,然后then()同理就可以是吧

那么我们现在就研究一下Promise.resolve()的一些特性:

如果向Promise.resolve()传递一个非Promise,非thenable的立即值,就会立即得到这个值填充的Promise,这个有三个关键字,非Promise,非thenable和立即值

如果向Promise.resolve()传递一个真正的promise,那么就会返回这个Promise,又一个例子,很好理解

var p = Promise.resolve(42);
var p2 = Promise.resolve(p);
console.log(p === p2);   // true

如果向Promise.resolve()传递一个非Promise的thenable值,那么就会展开这个值,并且在展开过程会持续到提取出一个具体的Promise最终值

大家应该会有一点疑惑,thenable是什么,这段话是什么意思

var obj = {then(resolve, reject) {resolve(42);}
};
Promise.resolve(obj).then((msg) => {console.log(msg);  //42
});

好了,Promise.resolve()特性讲完了,then返回值同理

同理完了以后呢,就会出现一些比较有意思的用法

首先就是链式调用,比如说

var p = Promise.resolve( 21 );
var p2 = p.then( function(v){console.log( v ); // 21// 用值42填充p2return v * 2;
} );
// 连接p2
p2.then( function(v){console.log( v ); // 42
} );

很简单吧,就不赘述了。

还有一个比较有意思,就是Promise实现同步执行,也就是前一个then如果是异步的话,它必须操作完成后,才会执行后面的then,常见的写法是这样的

new Promise((resolve, reject) => {setTimeout(() => {console.log('exec in promise it');resolve();}, 1000);
}).then(() => {return new Promise((resolve, reject) => {setTimeout(() => {console.log('exec in then it');resolve();}, 1000);});
});

这个先过一秒输出第一句话,再过一秒输出第二句话

这个的原理实际上刚刚Promise.resolve()的第二条,如果返回的是Promise,那么会直接返回这个Promise,在这里,直接返回return的这个Promise后,就会等待这个Promise决议,在一秒后决议完,就执行后面的then

最后一个有关then的知识点了:

一个Promise决议后,这个Promise上所有的通过then()注册的回调都会在下一个异步时间节点上依次被立即调用,这些回掉中任意一个都无法影响或者延误对其他回调的调用

var p = new Promise((resolve, reject) => {resolve();
});
p.then( function(){p.then( function(){console.log( "C" );} );console.log( "A" );
} );
p.then( function(){console.log( "B" );
} );
// a b c

这个的重点实际上是这些决议回调都被加入到了一个队列中,输出的顺序正好实际上就代表了他们加入队列后的先后顺序

参考书籍《你不知道的Javascript中卷》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/281031.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

psa name_Windows 10安全性PSA:启用自动商店更新

psa nameMicrosoft sometimes distributes important security updates through the Microsoft Store. That’s the lesson we’re learning in July 2020, when Microsoft sent an important update for Windows 10’s HEVC codecs not via Windows Update but via the Store.…

C# ListView 简单命令例子

编写工具常用到ListView控件,能简单列出选项,常用到流程校验显示。这里介绍简答显示,添加与删除功能。 1.添加表头,与显示。 this.listView1.Columns.Add("队列", 40, HorizontalAlignment.Left);this.listView1.Column…

手机照片丢失或误删如何恢复

手机照片丢失或误删如何恢复?我们每个人从刚出生就开始拍照片,一周岁照片、二周岁照片、三周岁照片等,因为照片可以记录我们从小到大的模样和变化。无意照片对我们每个人来说都很重要,如果手机突然坏以前的照片都找不到了怎么办呢…

C++学习笔记(二)——交换函数(swap)

这次我们要透过一个简单的函数swap深入理解函数传参的本质以及在C中如何选择传参方式。 先来看第一段程序: void swap(int x, int y) {int temp y;y x;x temp; } 通过main函数的调用,我们发现x,y并未实现交换: int main() {int x 1;int y…

大数据背后是个万亿市场

2014年的GDP中消费占比已经超过了50%,标志着中国经济正在向市场经济转型,消费占GDP50%-70%是中等发达国家向市场经济过渡的一个表现,未来中国经济增长最大的引擎应该来源于消费,特别是个人消费。中国正在经历经济结构调…

ipad iphone开发_如何将iPhone或iPad置于恢复模式

ipad iphone开发If your iDevice starts acting strangely and you’ve run through the gamut of normal troubleshooting fixes, Recovery Mode may be your answer. This lets you easily reset the device and re-install iOS using iTunes. 如果您的iDevice开始运行异常&a…

从三层架构说起,谈谈对历史项目的小改造

web development项目背景说明最近接手一个 “老” 项目的需求修改,项目整体基于 .net core 3.1 平台,以传统的三层架构为基础构建。了解需求后,逐步对原有项目框架进行大概的了解,主要是熟悉一些框架的开发规范,基本工…

C# message简单实现窗口间信息接收与发送

刚接触windows 不同程序 窗口消息传递,不理解IntPtr SendMessage(int hWnd, int msg, IntPtr wParam, IntPtr lParam)这函数怎么用?消息内容怎么传递过去,还遇到需要message结构体?IntPtr怎么用呢? 但实际只是用来传个…

在Kubernetes集群上部署和管理JFrog Artifactory

JFrog Artifactory是一个artifacts仓库管理平台,它支持所有的主流打包格式、构建工具和持续集成(CI)服务器。它将所有二进制内容保存在一个单一位置并提供一个接口,这使得用户在整个应用程序开发和交付过程中,能更易于…

已知思科ASA设备漏洞仍在其新版本中存在

近日,名为“Shadow Brokers(影子经纪人)”的黑客组织声称成功入侵了跟NSA相关的Equation Group(方程式组织)的计算机系统,并成功窃取到了大量的机密信息以及黑客工具。随后,“Shadow Brokers”黑客组织将60%的泄漏文件在网上进行了公布&#…

Yii Listview

转载于:https://www.cnblogs.com/xiong63/p/8546376.html

.NET 7 的 AOT 到底能不能杠反编译?

一:背景 1.讲故事在B站,公众号上发了一篇 AOT 的文章后,没想到反响还是挺大的,都称赞这个东西能抗反编译,可以让破解难度极大提高,可能有很多朋友对逆向不了解,以为用 ILSpy,Reflector,DnSpy 这…

google hdr+_更好的隐私权控制使Google+死了

google hdrEarlier this year, Google started a project to review third-party developer access to Google accounts through the use of APIs. It found a security breach surrounding Google, and is now shutting the service down, at least for consumers. 今年年初&a…

新0-Day漏洞或将给Linux桌面发行版带来浩劫

Linux 的各个发行版都一直强调安全及其相关元素,比如防火墙、渗透测试、沙盒、无痕上网和隐私等等,但事实上可能并没有想象中的那么安全。安全研究员 Chris Evans 公开了其发现的针对 Linux 桌面发行版的 0day 漏洞,利用特制的音频文件入侵 L…

一份详尽的利用 Kubeadm部署 Kubernetes 1.13.1 集群指北

2019独角兽企业重金招聘Python工程师标准>>> 概 述 Kubernetes集群的搭建方法其实有多种,比如我在之前的文章《利用K8S技术栈打造个人私有云(连载之:K8S集群搭建)》中使用的就是二进制的安装方法。虽然这种方法有利于我…

.NET性能优化-使用内存+磁盘混合缓存

我们回顾一下上一篇文章中的内容,有一个朋友问我这样一个问题:我的业务依赖一些数据,因为数据库访问慢,我把它放在 Redis 里面,不过还是太慢了,有什么其它的方案吗?其实这个问题比较简单的是吧&…

最小生成树详解

注:本文算法使用链式前向星数据结构实现。学习链接:链式前向星-学习笔记 一、Prim算法 普通prim算法模板: //用前向星录数据的时候记得把head初始化为-1 fill(dist,distLEN,MAX); memset(vis,0,sizeof vis); int ans0; dist[1]0; //如…

dropbox文件_Dropbox即将发布的扩展程序更新将添加更多文件编辑支持,包括Pixlr照片...

dropbox文件Dropbox is perhaps the best-known cloud storage platform for consumers, but it’s hoping to become something more. With an upcoming overhaul to its user tools, Dropbox will add more complex editing tools, in addition to what it already provides …

黑客窃取思科、IBM与甲骨文认证管理系统内的敏感数据

目前一套被思科、F5、IBM以及甲骨文等企业所广泛使用的认证管理系统(即Credential Manager System)正面临着数据泄露风险,其中的敏感数据也许已经被黑客们所获取。 根据Pearson VUE(主营计算机测试方案开发与交付)发布的一项公告,某恶意软件已经藏身于该…

Spring下载地址

下载地址:https://repo.spring.io/libs-release-local/org/springframework/spring/ 进入后可选择下载版本,选择版本后,进入目录结构。其中dist是最终发布版本,包含开发所需lib和源码。docs是开发文档。schema是一些约束文件。 Do…