Promise深入探索

栏目: JavaScript · 发布时间: 6年前

内容简介:假设我们要调用一个工具 foo(..) ,且并不确定得到的返回值是否是一个可信任的行为良好的 Promise,但我们可以知道它至少是一个 thenable。Promise.resolve(..) 提供了可信任的 Promise 封装工具对于用 Promise.resolve(..) 为所有函数的返回值(不管是不是 thenable)都封装一层。另一个好处是,这样做很容易把函数调用规范为定义良好的异步任务。如果 foo(42) 有时会返回一个立即值,有时会返回 Promise,那么 Promise.reso
  1. 如果向Promise.resolve()传递一个非promise非thenalbe的立即值,就会得到一个用这个值填充的promise。
  2. 如果向Promise.resolve()传递一个promise,就只会返回同一个promise
  3. 如果向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,但是它还是有一定的应用场景:

  1. 请求超时处理
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之类的回调函数用于处理这些被遗弃的孩子。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Creative Curve

The Creative Curve

Allen Gannett / Knopf Doubleday Publishing Group / 2018-6-12

Big data entrepreneur Allen Gannett overturns the mythology around creative genius, and reveals the science and secrets behind achieving breakout commercial success in any field. We have been s......一起来看看 《The Creative Curve》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具