promise解决的问题以及promise运行机制

这个是一个很大的话题。我已经看了好几遍了。总觉得都没有完全理解,

这次再总结一下。

回调可能产生的问题:

• 调用回调过早(在追踪之前);

• 调用回调过晚(或没有调用);

• 调用回调的次数太少或太多(就像你遇到过的问题!);

• 没有把所需的环境 / 参数成功传给你的回调函数;

• 吞掉可能出现的错误或异常;

 

调用过早:调用过晚 :回调未调用 

这个问题主要就是担心代码是否会引入类似 Zalgo 这样的副作用(参见第 2 章)。在这类问 题中,一个任务有时同步完成,有时异步完成,这可能会导致竞态条件。
 

Promise 就不必担心调用过早的问题,因为即使是立即完成的Promise,也总会被异步调用,插在事件队列的末尾。

 

 

Promise 创建对象调用resolve(..) 或 reject(..) 时,这个Promise 的 then(..) 注册的观察回调就会被自动调度。可以确信,这些被调度的回调在下一个异步事 件点上一定会被触发

 

 

你对一个 Promise 注册了一个完成回调和一个拒绝回调,那么 Promise 在决议时总是会调用其中的一个;

如果Promise 本身永远不被决议,还可以通过

// 用于超时一个Promise的工具 
function timeoutPromise(delay) {      
return new Promise( function(resolve,reject){          
setTimeout( function(){             
 reject( "Timeout!" );          
}, delay );     
 } ); 
 }  
 
// 设置foo()超时 
Promise.race( [      
foo(),                     
 // 试着开始foo()       
timeoutPromise( 3000 )      
// 给它3秒钟 
] )  
.then(      
function(){         
 // foo(..)及时完成!     
 }, 

调用次数过少或过多 

promise本身只能被决议一次,但是如果你回调事件注册了两次,那它被调用 的次数就会和注册次数相同。

未能传递参数 / 环境值 

你没有用任何值显式决议,那么这个值就是 undefined,如果使用多个参数调用 resovle(..) 或者 reject(..),第一个参数之 后的所有参数都会被默默忽略。

吞掉错误或异常

如果拒绝一个 Promise 并给出一个理由(也就是 一个出错消息),这个值就会被传给拒绝回调。
如果在Promise 的创建过程中或在查看其决议 结果过程中的任何时间点上出现了一个JavaScript 异常错误,比如一个TypeError 或 ReferenceError,那这个异常就会被捕捉,并且会使这个 Promise 被拒绝。


Promise可信任问题

Promise会包装他接收到参数;

如果向 Promise.resolve(..) 传递一个非 Promise、非 thenable 的立即值,就会得到一个用 这个值填充的 promise。

如果向 Promise.resolve(..) 传递了一个非 Promise 的 thenable 值,前者就会 试图展开这个值,而且展开过程会持续到提取出一个具体的非类 Promise 的最终值。

var p = {      
then: function(cb,errcb) {        
  cb( 42 );         
 errcb( "evil laugh" );     
 }  
};  
 
p  
.then(      
function fulfilled(val){          
console.log( val ); // 42      
},  
 
    function rejected(err){          
// 啊,不应该运行!          
console.log( err ); 
// evil laugh      
}  
); 

这个 p 是一个 thenable,但是其行为和 promise 并不完全一致,它都是不可信 任的。

尽管如此,我们还是都可以把这些版本的 p 传给 Promise.resolve(..),然后就会得到期望,中的规范化后的安全结果:Promise.resolve(..) 可以接受任何 thenable,将其解封为它的非 thenable 值。从 Promise. resolve(..) 得到的是一个真正的 Promise,是一个可以信任的值。

让我们来简单总结一下使链式流程控制可行的 Promise 固有特性


• 调用 Promise 的 then(..) 会自动创建一个新的 Promise 从调用返回。

• 在完成或拒绝处理函数内部,如果返回一个值或抛出一个异常,新返回的(可链接的) Promise 就相应地决议。

• 如果完成或拒绝处理函数返回一个 Promise,它将会被展开,这样一来,不管它的决议 值是什么,都会成为当前 then(..) 返回的链接 Promise 的决议值。

// 步骤1:
 request( "http://some.url.1/" )  
 
// 步骤2:
 .then( function(response1){      
foo.bar(); // undefined,出错! 
 
    // 永远不会到达这里      
return request( "http://some.url.2/?v=" + response1 );  } )  
 
// 步骤3:
 .then(    
  function fulfilled(response2){      
    // 永远不会到达这里    
  },  
 
    // 捕捉错误的拒绝处理函数    
  function rejected(err){     
     console.log( err );     
     // 来自foo.bar()的错误TypeError   
       return 42;     
 }  )  
 
// 步骤4:
 .then( function(msg){    
  console.log( msg );       
    // 42 
 },
function(err){
console.log(err)
} );
var rejectedTh = {      
then: function(resolved,rejected) {          
rejected( "Oops" );      }  };  
 
var rejectedPr = Promise.resolve( rejectedTh ); 

Promise.resolve(..) 会将传入的真正Promise 直接返回,对传 入的thenable 则会展开。
如果这个thenable 展开得到一个拒绝状态,那么从Promise. resolve(..) 
返回的 Promise 实际上就是这同一个拒绝状态。

所以resolve是一个完成的状态,它可能会获得一个成功也可能是失败。

Promise的问题:

会容易吞掉错误

var p = Promise.resolve( 42 );  
 
p.then(     
 function fulfilled(msg){       
   // 数字没有string函数,所以会抛出错误     
    console.log( msg.toLowerCase() );    
  },      
function rejected(err){    
      // 永远不会到达这里   
  }  
);

如果 msg.toLowerCase() 合法地抛出一个错误(事实确实如此!),为什么我们的错误处理 函数没有得到通知呢?
正如前面解释过的,这是因为那个错误处理函数是为 promise p 准 备的,而这个 promise 已经用值 42 填充了。
promise p 是不可变的,所以唯一可以被通知这 个错误的 promise 是从 p.then(..) 返回的那一个,但我们在此例中没有捕捉。



无法取消的 Promise 

一旦创建了一个 Promise 并为其注册了完成和 / 或拒绝处理函数,如果出现某种情况使得 这个任务悬而未决的话,你也没有办法从外部停止它的进程。
 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值