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,一经查实,立即删除!

相关文章

linux进阶命令2

linux进阶命令2 压缩1.压缩的概念1)压缩的目的: 在网络传递文件时,可以先将文件压缩,然后传递压缩后的文件,从而减少网络带宽。 接受者接受文件后,解压即可。2)压缩的类型 有损压缩、无损压缩。…

PHP经常使用正則表達式汇总

1. 平时做站点常常要用正則表達式,以下是一些解说和样例,仅供大家參考和改动使用: 2. "^\d$"  //非负整数(正整数 0) 3. "^[0-9]*[1-9][0-9]*$"  //正整数 4. "^((-\d)|…

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#并行编程-Task

什么是异步同步和异步主要用于修饰方法。当一个方法被调用时,调用者需要等待该方法执行完毕并返回才能继续执行,我们称这个方法是同步方法;当一个方法被调用时立即返回,并获取一个线程执行该方法内部的业务,调用者不用…

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

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

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

Git 操作笔记/pip换源

pip换源 阿里云的源,在cmd命令行中输入上述命令即可 pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/ 还原commit 不可逆 1.git log2.选择某次提交的commit ID3.使用git reset --hard commit ID 远程查看与断开 git remote -vgit remote rem…

.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…

php中把美国时间转为北京时间的自定义

我的服务器北京时间,php调用的时间: date.timezone "America/Chicago" 这是美国这边的一个时间,有的时候跟北京相差13个小时,有的时候跟北京时间相差14个小时,所以很不好处理,现在php函数就能处…

C# DataTable笔记

文章转载自http://www.cnblogs.com/Sandon/p/5175829.html 感谢博主Sandon。 为了方便以后编程查看,特把文章复制过来。 创建表 //创建一个空表 DataTable dt new DataTable(); //创建一个名为"Table_New"的空表 DataTable dt new DataTable("Tabl…