通过一道笔试题浅谈javascript中的promise对象
因为前几天做了一个promise对象捕获错误的面试题目,所以这几天又重温了一下promise对象。现在借这道题来分享下一些很基础的知识点。
下面是一个面试题目,三个promise对象捕获错误的例子,返回结果有什么不同。
//使用throw添加错误事件
var p = new Promise(function(resolve, reject) {
resolve("ok");
throw new Error('error0');
//setTimeout(function() { throw new Error('error1') }, 0);
});
p.then(function(value){
console.log(value)
})
.catch(funcrion(err){
console.log(err)
});
process.on('unhandledRejection', function (err, p) { console.error('catch exception:',err.stack) });
//设置定时器来抛出错误事件
var p = new Promise(function(resolve, reject) {
resolve("ok");
//throw new Error('error0');
setTimeout(function() { throw new Error('error1') }, 0);
});
p.then(function(value){
console.log(value)
})
.catch(funcrion(err){
console.log(err)
});
process.on('unhandledRejection', function (err, p) { console.error('catch exception:',err.stack) });
//同时添加错误事件
var p = new Promise(function(resolve, reject) {
resolve("ok");
throw new Error('error0');
setTimeout(function() { throw new Error('error1') }, 0);
});
p.then(function(value){
console.log(value)
})
.catch(funcrion(err){
console.log(err)
});
process.on('unhandledRejection', function (err, p) { console.error('catch exception:',err.stack) });
先把问题放在这里,如果一眼能看出结果的大大们就不用再往下面读了。。
大概在很早以前就有了解过javascript中实现异步编程的四种方式。分别是1.回调函数 2.事件监听 3.发布、订阅事件 4.promise对象
前三种我们可以说是屡见不鲜了,回调函数,事件监听这算是js的“灵魂”了。。发布、订阅事件也是比较常见的。今天我们就来浅显学习下promise对象,以及它能实现异步编程的原理,最后是上面那个题目的答案以及我个人的一些理解。
一、什么是promise对象,它能干什么?
Promises对象是在CommonJS工作组提出的一种规范,目的是为异步编程提供统一接口。现已在ECMAScript2015(ES6)中实现。
Promise
对象用于延迟(deferred) 计算和异步(asynchronous ) 计算.。一个Promise对象代表着一个还未完成,但预期将来会完成的操作。
Promise
对象是一个返回值的代理,这个返回值在promise对象创建时未必已知。它允许你为异步操作的成功或失败指定处理方法。 这使得异步方法可以像同步方法那样返回值:异步方法会返回一个包含了原返回值的 promise 对象来替代原返回值。
Promise
对象有以下几种状态:
pending: 表示一个初始状态, 非 fulfilled 或 rejected。
fulfilled: 成功的操作。
rejected: 失败的操作。
每一个异步任务都会返回一个Promise对象,该对象有一个then方法,允许指定回调函数。可以根据Promise对象的状态相应的去执行对应的回调函数。我们大概了解了promise存在的意义,下面我们具体去看一下该对象常用的几个API。
二、常用的API
1.Promise.prototype.then()
promise实例具有then方法,因此then方法是定义在原型对象promise.prototype上的。它的作用是为promise实例添加状态改变时的回调函数。
then()方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。then方法返回的是一个新的promise实例,非原来的那个promise实例,因此可以采用链式写法,then方法之后还可调用一个then方法。
var p=new Promise(function(resolve,eject){
resolve("ok");
});
p.then(function(value){console.log(val)},
function(err)(console.log(err))
);
then方法的第二个参数一般不推荐写。有以下两个原因:第一个原因,由于是链式操作,这个then方法之后还可能会有其他操作,如果此时把错误捕捉的函数放在后面方法前边的话,并且之后再无错误捕获方法,then之后的错误就会捕捉不到。第二个原因是在then方法里面,两个参数都是回调函数写了一大堆,这样结构看起来比较混乱。
所以下面就有了这个方法,一般写在链式写法的最后。这样就可以捕获到前面所有的错误。
2.Promise.prototype.catch()
这个方法是.then(null,rejection)的别名,这也能看出这个方法是专门只能用来捕获错误信息,用于指定发生错误时的回调函数。
但是使用这个这个方法的时候要注意一下几点:
(1)当promise状态已经变成resolved的时候,再抛出错误时是无效的。看下面的代码。
var promise=new promise(function(resolve,reject){
resolve("ok");
throw new Error("test");
});
promise.then(function(value){consloe.log(val); })
.catch(function(error){console.log(err)});
promise状态在resolve("ok");之后就会把promise的状态变为resolved,之后抛出错误也不会把promise状态变为rejected,所以catch方法并不会捕获到错误。
Promise 对象的状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变为 Rejected。只要这两种情况有任意一种发生,状态就相当于凝固了,不会再变了,会一直保持这个结果。
(2)尽量将catch方法写在链式操作的最后,原因上面都已经说过了,也正是捕获错误不推荐写then方法的原因之一。错误会一直冒泡到最后,catch放在最后会捕捉到所有错误。当catch设置的过早,并且之后在没有catch方法的话,那么这个catch之后发生的错误不会被捕获到。
(3)当没有使用catch方法指定错误处理函数的回调函数时,promise对象里面抛出的错误不会传递到外层的代码。
3.Promise.resolve()
这个方法的作用就是将现有的对象转化为Promise对象,进而可以执行这些方法。
Promise.resolve("foo"); //这就相当于下面这种写法 new Promise(function(resolve){
resolve("foo");
});
4.Promise.all()
这个方法用于将多个promise实例,包装成一个新的promise实例。
var p=Promise.all([p1,p2,p3]);
p1,p2,p3都是promise对象的实例,如果不是的话,则会调用Promise.resolve()方法,将参数转化为Promise实例,之后再继续进行进一步的处理。
并且要注意一下两点:
(1)只有当p1,p2,p3状态都变为fulfilled之后,p的状态才会变为fulfilled。
(2)只要p1.p2,p3中有任意一个状态变为rejected,p的状态就会变为rejected。
三、实现异步编程的原理
大概原理就是正如它们所说Promise对象相当于是一个状态机,在其内部使用resolve方法,使其由初始状态变为成功时的fulfilled状态或者执行失败后的rejected状态。这时内部的工作就完成了,开始由外部监听其内部的状态的改变,调用then()方法(catch()方法相当于then内部的第二个参数方法)对应的状态调用对应的处理函数。这样就大概是Promise对象实现异步编程的原理。
四、开头所给问题的答案
我们可以看到三个实例外部函数的写法一模一样,不同的是Promise对象内部抛出错误所使用的方法。
第一个使用throw抛出错误,理应被外部的catch方法所捕获到。但是但是。。之前已经说过Promise对象状态一旦被改变之后就“凝固”了,一旦执行
resolve("ok");
状态被设定为fulfilled之后,再进行抛出错误处理,错误也不会被后续的catch方法捕获到。所以这里只会去执行then()方法里面的内容。即只会打印出 “ok”。
第二个通过定时器抛出一个错误。这里虽然状态已经变为fulfilled,但是定时器抛出的错误属于异步抛出的错误,无法被try catch捕获到,因此和Promise对象无关,所以错误可以正常的抛出来,所以这里的答案应该是先打印出“ok”,之后抛出process里面定义的错误。
第三个同时使用throw和定时器抛出错误。是不是里应当和第二个执行情况一样吗?这样想就错了。当执行throw之后,虽然错误未被外部函数捕获处理,但这也是个实实在在存在的错误啊,对于javascript来说,有错就不会继续往下面执行了。所以并不会执行到定时器抛出错误就停止了。因此这个问题的答案应该是 只打印出“ok”。
嗯,结束。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
通过一道笔试题浅谈javascript中的promise对象的更多相关文章
- 面试题-浅谈JavaScript中的This指向问题
各位小伙伴在面试中被面试官问道this指向问题一定不少吧,同时还被问道apply,call和bind的用法区别,现在,就来简单的聊一聊this到底指向何方. 1.基本概念 MDN的官方解释:与其他语言 ...
- 浅谈JavaScript中的闭包
浅谈JavaScript中的闭包 在JavaScript中,闭包是指这样一个函数:它有权访问另一个函数作用域中的变量. 创建一个闭包的常用的方式:在一个函数内部创建另一个函数. 比如: functio ...
- 浅谈JavaScript中的null和undefined
浅谈JavaScript中的null和undefined null null是JavaScript中的关键字,表示一个特殊值,常用来描述"空值". 对null进行typeof类型运 ...
- 浅谈JavaScript中的正则表达式(适用初学者观看)
浅谈JavaScript中的正则表达式 1.什么是正则表达式(RegExp)? 官方定义: 正则表达式是一种特殊的字符串模式,用于匹配一组字符串,就好比用模具做产品,而正则就是这个模具,定义一种规则去 ...
- 一道笔试题来理顺Java中的值传递和引用传递
题目如下: private static void change(StringBuffer str11, StringBuffer str12) { str12 = str11; str11 = ...
- 浅谈JavaScript中的Function引用类型
引言 在JavaScript中最有意思的就是函数了,这一切的根源在于函数实际上是一个对象.每一个函数都是Function类型的实例,而且都和其他引用类型的实例一样具有属性和方法.函数作为一个对象,因此 ...
- 浅谈 JavaScript 中的继承模式
最近在读一本设计模式的书,书中的开头部分就讲了一下 JavaScript 中的继承,阅读之后写下了这篇博客作为笔记.毕竟好记性不如烂笔头. JavaScript 是一门面向对象的语言,但是 ES6 之 ...
- 浅谈JavaScript中的内存管理
一门语言的内存存储方式是我们学习他必须要了解的,接下来让我浅谈一下自己对他的认识. 首先说,JavaScript中的变量包含两种两种类型: 1)值类型或基本类型:undefined.null.numb ...
- 浅谈JavaScript中闭包
引言 闭包可以说是JavaScript中最有特色的一个地方,很好的理解闭包是更深层次的学习JavaScript的基础.这篇文章我们就来简单的谈下JavaScript下的闭包. 闭包是什么? 闭包是什么 ...
随机推荐
- Android使用ListView应该注意的地方
在ListView中设置Selector为null会报空指针? mListView.setSelector(null);//空指针 试试下面这种: mListView.setSelector(new ...
- js jquery实时计算输入字符
在项目中需要倒还可以输入多少字符
- Oracle笔记1-数据库概念
数据库: 基本的概念:数据库管理系统(Database Management System,DBMS):管理数据的一个软件系统关系型数据库管理系统(RDBMS)数据库(Database):存放数据的磁 ...
- iOS与JS交互实战篇(ObjC版)
前言 ObjectiveC与Js交互是常见的需求,可对于新手或者所谓的高手而言,其实并不是那么简单明了.这里只介绍iOS7.0后出来的JavaScriptCore framework. 关于JavaS ...
- MediaCodec Name & Type
OMX.google.mp3.decoder support type:audio/mpegOMX.google.amrnb.decoder support type:audio/3gppOMX.go ...
- js-PC版监听键盘大小写事件
//获取键盘按键事件,可以使用keyup. //问题:获取到键盘的按下Caps lock键时,不能知道当前状态是大写.还是小写状态. //解决: 设置一个全局判断大小写状态的 标志:isCapital ...
- ubuntu 14.04 下通过apt-get 安装jdk
Installing default JRE/JDK sudo apt-get update sudo apt-get install default-jre sudo apt-get install ...
- OpenGL观察轴
旋转矩阵可以通过观察向量构造,观察向量可以是3D空间的两个或三个点.如果一个处于P1点的对象面向P2点,则观察向量就是P2-P1,如下图: 首先,前轴向量通过归一化的观察向量简单计算而来. 其次,左轴 ...
- 简介 – ASP.NET MVC 4 系列
正所谓好记性不如烂笔头,尤其是技术类书籍在阅读后,时间久了一定会忘记.而重新翻阅整本书也较为低效,遂以博客记录阅读摘要以供日后查阅.本系列文章均摘要自 Wrox 红皮书[ASP.NET ...
- Businessworks的设计思想
Businessworks的设计思想基于一下三篇ATA: <从Eclipse平台看交易平台化>,强调微内核和扩展机制实现 <Google Guice平台模块化开发的果汁>,讨论 ...