Promise深入探索
栏目: JavaScript · 发布时间: 5年前
内容简介:假设我们要调用一个工具 foo(..) ,且并不确定得到的返回值是否是一个可信任的行为良好的 Promise,但我们可以知道它至少是一个 thenable。Promise.resolve(..) 提供了可信任的 Promise 封装工具对于用 Promise.resolve(..) 为所有函数的返回值(不管是不是 thenable)都封装一层。另一个好处是,这样做很容易把函数调用规范为定义良好的异步任务。如果 foo(42) 有时会返回一个立即值,有时会返回 Promise,那么 Promise.reso
- 如果向Promise.resolve()传递一个非promise非thenalbe的立即值,就会得到一个用这个值填充的promise。
- 如果向Promise.resolve()传递一个promise,就只会返回同一个promise
- 如果向Promise.resolve()传递了一个非Promise的thenable值,前者会试图展开这个值,而且展开过程中会持续到提取出一个具体的非类Promise的最终值。
假设我们要调用一个工具 foo(..) ,且并不确定得到的返回值是否是一个可信任的行为良好的 Promise,但我们可以知道它至少是一个 thenable。Promise.resolve(..) 提供了可信任的 Promise 封装工具
// 不要只是这么做: foo( 42 ) .then( function(v){ console.log( v ); } ); // 而要这么做: Promise.resolve( foo( 42 ) ) .then( function(v){ console.log( v ); } ); 复制代码
对于用 Promise.resolve(..) 为所有函数的返回值(不管是不是 thenable)都封装一层。另一个好处是,这样做很容易把函数调用规范为定义良好的异步任务。如果 foo(42) 有时会返回一个立即值,有时会返回 Promise,那么 Promise.resolve( foo(42) ) 就能够保证总会返回一个 Promise 结果
默认错误处理函数
如果一个promise链中的上一级promise抛出一个错误,但是下一级promise并没有配置错误处理函数,promise会有一个默认处理函数来处理这个错误,即吧这个错误重新抛出给下一级promise的错误处理函数。
如果一直找到最后一级的promise都没有错误处理函数,那么promise会在控制台打出一个错误信息,并且这个错误是有可能中断nodejs进程的。
DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code. 复制代码
(在浏览器环境貌似并不会中断进程)
Promise链
- 调用promise的then方法,会自创建一个新的Promise,并且决议的值就是then中resolve/reject函数的返回值;
- 如果resolve/reject函数返回的是一个Promise,那么会等待这个Promise的决议结果,并将决议结果作为当前then方法生成的Promise的决议值;
var a = new Promise(function(resolve, reject) { resolve(10) }).then( res => { return b } ).then(res => { console.log('1err:' + res) return res }).then(res => { console.log('1res:' + res) return res }, err => { console.log('2err:' + err) }) var b = new Promise(function(resolve, reject) { resolve(123123123123) }) 复制代码
Promise构造器中两个回调函数
reject很好理解就是处理错误,那么resolve为什么不用fulfill呢?貌似应该是处理成功请求?实际上resolve的意思是决议,也就是可能是成功的结果也可能是失败的结果;比如所给resolve传入thenable或者一个真正的Promise,这个时候决议的结果取决于返回值的决议结果,所以说resolve返回的有可能是成功也有可能是失败;
var rejectedPr = new Promise( function(resolve,reject){ // 用一个被拒绝的promise完成这个promise resolve( Promise.reject( "Oops" ) ); } ); rejectedPr.then( function fulfilled(){ // 永远不会到达这里 }, function rejected(err){ console.log( err ); // "Oops" } ); 复制代码
前面提到的 reject(..) 不会像 resolve(..) 一样进行展开。如果向 reject(..) 传入一个 Promise/thenable 值,它会把这个值原封不动地设置为拒绝理由。后续的拒绝处理函数接收到的是你实际传给 reject(..) 的那个 Promise/thenable,而不是其底层的立即值。
回调函数简介
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应
而then方法的两个回调函数应该使用onFulfilles/fulfilled和onRejected/rejected因为对于then来说第一个回调只能处理正确的结果。
(fulfilled the promis 兑现承诺)
Promise错误处理函数的细节
通常我们有两种写法来捕获错误:
var a = new promise(function(resolve, reject){}) // 在then方法的内部第二个回调捕获 a.then(res => { }, err => { }) // 在catch方法中捕获 a.then(res => {}).catch(err => {}) 复制代码
那么这两种方法有什么不同? 实际上第二种方法是包含第一种方法的,只不过then方法中的第二个回调被默认执行了,而默认的错误处理回调只是简单的抛出错误,然后就会被catch方法捕获; 这里就有一个问题,如果a的决议是resolve,那么就会调用then的第一个成功回调,如果这个成功回调中的具体代码中发生了错误,第一种方法是无法捕获的,而第二种方法是可以捕获的。
var a = new promise(function(resolve, reject){ resolve(12) }) // 在then方法的内部第二个回调捕获 a.then(res => { aaa() // 这里aaa是不存在的会发生错误 }, err => { console.log(err) // 不会走这里,所以错误不会被捕获 }) // 在catch方法中捕获 a.then(res => { aaa() // 这里aaa是不存在的会发生错误 }).catch(err => { console.log(err) // 这里会捕获then方法中的所有错误,自然也能捕获aaa导致的错误 }) 复制代码
Promise.race()的应用场景
实际上Promise.race([p1, p1, p3])这种模式在程序设计中通常是一种被称为竞态的bug,但是它还是有一定的应用场景:
- 请求超时处理
var p1 = new Promise(function(resolve, reject) { setTimeout(function() { resolve(2222) }, 2000) }) // 定义一个超时函数,如果p1超过这个时间还未决议,就认为这个请求超时了。 var timeoutPromise = new Promise(function(resolve, reject) { setTimeout(function() { reject('timeout') }, 1000) }) Promise.race([p1, timeoutPromise]).then(res => { console.log(res) }).catch(err => { console.log(err) }) 复制代码
有时候我们可能会想,Promsie.race()中那些别丢弃(比赛中失败)的Promise哪里去了?当然最后会被垃圾回收,但是,Promsie不能别停止,它们依旧会完成自己的任务直到决议,目前来看只是被默默的丢弃了,像空气一样,或许在以后的规范中会添加类似与finally之类的回调函数用于处理这些被遗弃的孩子。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 深入探索WebSockets
- 深入探索 Android 启动速度优化
- 深入探索 Typescript 的高阶用法
- 深入探索Android布局优化(上)
- Java并发计数器深入探索
- 深入探索 Android Gradle 插件的缓存配置
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Java常用算法手册
2012-5 / 59.00元
《Java常用算法手册》分三篇,共13章,分别介绍了算法基础、算法应用和算法面试题。首先介绍了算法概述,然后重点分析了数据结构和基本算法思想;接着,详细讲解了算法在排序、查找、数学计算、数论、历史趣题、游戏、密码学等领域中的应用;最后,列举了算法的一些常见面试题。书中知识点覆盖全面,结构安排紧凑,讲解详细,实例丰富。全书对每一个知识点都给出了相应的算法及应用实例,虽然这些例子都是以Java语言来编......一起来看看 《Java常用算法手册》 这本书的介绍吧!