面试考察之Promise对象

这篇博客主要探讨了Promise在面试中的常见问题,包括Promise构造函数的参数类型和执行时机,多次调用resolve或reject的影响,以及异常处理。还讨论了Promise的原理,jQuery的ajax返回的对象类型,以及如何确保一个函数在Promise的任何状态下都能被调用。Promise.all()的用法和处理异步任务的场景也被详细解释,同时提到了Promise的finally方法和done方法在处理错误时的角色。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Promise方法你最常用什么写法?构造函数传入的参数是什么类型?(我回答的是匿名函数)那么,传入的该函数是会立刻执行的吗?若调用了两次resolve方法会怎么样?发生异常会怎么样?

Promise是一个构造函数,自己身上有all、race、reject、resolve这几个眼熟的方法,原型上有then、catch等同样很眼熟的方法。这么说用Promise new出来的对象肯定就有then、catch方法喽。
当通过Promise构造函数实例化一个对象时,会传递一个函数作为参数,而且这个函数在新建一个Promise后,会立即执行。所以传入的该函数是会立刻执行的。

会在本次new 操作立刻执行。。
第一次resove就确定了自己是成功还是失败。第二次没用了。添加reject也改变不了。
Promise 一旦决议了,之后的决议就没有用了,状态无法改变的。会忽略

补充resolve方法的两个用途:(1)改变状态;(2)传参
我们会在异步操作成功时调用resolve函数,其作用是将Promise对象的状态从Pending变为Resolved,并将异步操作的结果,作为参数传递给Fulfilled状态的回调函数。

发生异常分为以下几种情况:
参考:http://www.cnblogs.com/lvdabao/p/es6-promise-1.html

promise的原理?jquery的ajax返回的是promise对象吗?(百度面试)

jquery的ajax返回的是deferred对象,通过promise的resolve()方法将其转换为promise对象。

var jsPromise = Promise.resolve($.ajax('/whatever.json'));

promise 只有2个状态,成功和失败,怎么让一个函数无论成功和失败都能被调用? Promise.all() 是干什么用的,怎么用?

promise.all()的使用:
Promise.all方法用于将多个Promise实例,包装成一个新的Promise实例。

Promise.all方法接受一个数组作为参数,数组里的元素都是Promise对象的实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为Promise实例,再进一步处理。(Promise.all方法的参数可以不是数组,但必须具有Iterator接口,且返回的每个成员都是Promise实例。)

var p =Promise.all([p1,p2,p3]);

p的状态由p1、p2、p3决定,分为两种情况。

  • 当该数组里的所有Promise实例都进入Fulfilled状态,Promise.all**返回的实例才会变成Fulfilled状态。并将Promise实例数组的所有返回值组成一个数组传递给Promise.all返回实例的回调函数**。
  • 当该数组里的某个Promise实例都进入Rejected状态,Promise.all返回的实例会立即变成Rejected状态。并将第一个rejected的实例返回值传递给Promise.all返回实例的回调函数。

怎么让一个函数无论promise对象成功和失败都能被调用?

笨方法:

在两个回调中分别执行一次函数。

推荐方式:

扩展一个 Promise.finally(),finally方法用于指定不管Promise对象最后状态如何,都会执行的操作,它与done方法的最大区别在于,它接受一个普通的回调函数作为参数,该函数不管怎样都必须执行。

http://es6.ruanyifeng.com/#do…两个有用的附加方法

//添加finally方法
Promise.prototype.finally=function (callback) {
   var p=this.constructor;
   return this.then(//只要是promise对象就可以调用then方法
     value => p.resolve(callback()).then(() => value),
     reason => p.resolve(callback()).then(() => {throw reason})
   );
}

对finally方法的理解:(1)p.resolve(callback())这句函数callback已经执行
(2)finally方法return的是一个promise对象,所以还可以继续链式调用其他方法
(3)对于Promise.resolve方法

Promise.resolve('foo');
等价于
new Promise(resolve => resolve('foo'));

所以可以通过then方法的回调函数 接受 实例对象返回的参数
比如:

Promise.resolve(function(){console.log(2);}).then(function(cb){cb()}) 

(4)p.resolve(callback()).then(() => value)调用then的目的是给promise实例即this添加成功和失败的回调函数

使用promise需注意:

古人云:“君子一诺千金”,这种“承诺将来会执行”的对象在JavaScript中称为P**romise对象**。参考:https://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/0014345008539155e93fc16046d4bb7854943814c4f9dc2000

Promise是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6将其写进了语言标准,统一了用法,原生提供了Promise对象
本文所描述的Promise指Promises/A+规范定义的Promise,可参考Promise/A+,一个可靠的可共同协作的JavaScript Promise开放标准。
Promise是CommonJs的规范之一,包含resolve,reject,done,fail,then等方法,能够帮助我们控制代码的流程,避免函数的多层嵌套。异步在web开发中越来越重要,对于开发人员来说,J**非线性执行的编程会让开发者觉得难以掌控,而Promise可以让我们更好地掌控代码的执行流程,jQuery等流行的**js库都已经实现了这个对象,现在ES6已经原生实现了Promise。
参考:http://www.cnblogs.com/linda586586/p/5592040.html

promise的构造函数为匿名函数,该函数的两个参数为resolve和reject,他们是两个函数。

resolve和reject的作用:1、resolve用来将Promise对象的状态置为成功,并将异步操作结果value作为参数传给成功回调函数。(两个作用)
注意:只要promise实例的状态变为resolved回调函数就会立即执行。

2、reject用来将Promise对象的状态置为失败,并将异步操作错误error作为参数传给失败回调函数。

使用promise代替地狱式回调函数的好处:
这种写法被称为 composing promises ,是 promises 的强大能力之一。这样写可以带来好处:

  • 清晰的代码结构。
  • 避免始料不及的错误。进行快速的问题定位,避免难以调试更甚至于失败了而没有任何反馈。

then方法的参数:两个回调函数,第一个回调函数是promise的状态变为resolved时调用,第二个回调函数时promise的状态变为rejected时调用,第二个函数可选,不一定提供这两个函数都接受promise对象传出的值作为参数。(熟悉then的用法)

promise.all()的使用:
Promise.all方法用于将多个Promise实例,包装成一个新的Promise实例。

Promise.all方法接受一个数组作为参数,数组里的元素都是Promise对象的实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为Promise实例,再进一步处理。(Promise.all方法的参数可以不是数组,但必须具有Iterator接口,且返回的每个成员都是Promise实例。)

  • 当该数组里的所有Promise实例都进入Fulfilled状态,Promise.all返回的实例才会变成Fulfilled状态。并将Promise实例数组的所有返回值组成一个数组传递给Promise.all返回实例的回调函数

当该数组里的某个Promise实例都进入Rejected状态,Promise.all返回的实例会立即变成Rejected状态。并将第一个rejected的实例返回值传递给Promise.all返回实例的回调函数。

Promise.race方法跟Promise.all方法差不多。唯一的区别在于该方法返回的Promise实例并不会等待所有Proimse都跑完,而是只要有一个*Promise实例改变状态,它就跟着改变*状态。并使用第一个改变状态实例的返回值作为返回值。

var p=Promise.race([p1,p2,p3]);

promise.resolve():该方法的作用是将现有对象转为promise对象。

Promise.resolve('foo');
等价于
new Promise(resolve => resolve('foo'));

promise.reject():会返回一个新的promise实例,状态为rejected

var p = Promise.reject('出错了');
//等价于
var p = new Promise((resolve,reject) => reject('出错了'));//注意:Promise的参数为匿名函数,resolve不能写为null
p.then(null,function (s) {//then的两个参数也都为匿名构造函数
  console.log(s)
})

注意

细节一:
resolve(value) VS resolve(promise)
ps:resolve方法传入的实参不限于值类型或者Promise实例。更多内容请参考Promise/A+。具体参考:http://imweb.io/topic/57a0760393d9938132cc8da9

细节二:
then方法返回的是一个新的Promise实例(注意是新的)
重要的事情要说三遍。这也是我们能够使用第二节中的链式写法的最重要原因(结合例子理解)

细节三:

var d = new Date();

var promise1 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 1000, 'resolve from promise1');
    // setTimeout(reject, 1000, 'reject from promise1');
});

var promise2 = promise1.then(function(result) {
    console.log('promise1.then(resolve):', result);
    return result;
}, function(error) {
    console.log('promise1.then(reject):', error);
    return error;
});

promise2.then(
    result => console.log('result:', result, new Date() - d),
    error => console.log('error:', error, new Date() - d)
)

// promise1.then(resolve): resolve from promise1
// result: resolve from promise1 1012

通过运行上面的例子,我们会发现promise的状态无论是fulfilled或者rejected,其绑定的.then方法返回的Promise实例(即promise2)都只会执行它的onFulfilled回调方法。(???)

细节四:
所以这里作者给的建议是:在回调方法中一定要有return语句,放弃在回调方法中使用return,相当于放弃获取在该回调方法中的所有操作结果

细节五:
这就是Promise的状态透传特点,如果当前的promise实例没有绑定回调函数或者绑定的不是函数,那么当前实例就会把其状态以及不可变值或者不可变原因传递给当前实例调用.then方法返回的新promise实例。

细节六
对使用第二个回调函数处理错误存在的两个问题有所了解,一般使用catch()方法进行错误捕获。

promise的使用场景:
1,用于取代回调函数解决异步操作。
2.Promise最大的好处是在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了
3.Promise还可以做更多的事情,比如,有若干个异步任务,需要先做任务1,如果成功后再做任务2,任何任务失败则不再继续并执行错误处理函数。
串行执行这样的异步任务,不用Promise需要写一层一层的嵌套代码。有了Promise,我们只需要简单地写:

job1.then(job2).then(job3).catch(handleError);

对js中异步操作的理解:
程序不按顺序执行,下一步操作不用等待上一步。

两个有用的附加方法

一、done()
用途:
promise对象的回调链,不管以then方法或catch方法结尾,要是最后一个方法抛出错误,都有可能无法捕捉到(因为Promise内部的错误不必冒泡到全局)。为此,我们可以提供一个done方法,总是处于回调链的尾端,保证抛出任何可能出现的错误。

asyncFunc()
 .then(f1)
 .catch(r1)
 .then(f2)
 .done();

 //done方法实现
 Promise.prototype.done = function (onFulfilled,onRejected) {
   this.then(onFulfilled,onRejected).catch(function (reason) {
      setTimeout(() => {throw reason},0);
   })
}

对done方法的理解:
(1)由上可见,done方法可以像then方法那样用,提供Fulfilled和Rejected状态的回调函数,也可以不提供任何参数。但不管怎样,done方法都会捕捉到任何可能出现的错误,并向全局抛出。
(2)done方法主要是基于Promise.catch()方法实现的。
(3)使用setTimeout,它为宏观任务,在主线程事件完成后,再执行该操作。

done()和then()捕获异常的区别
1、then支持延续任务调用方式(Continuation tasks),而done不支持
比如then可以这样用,而done不可以:
promise().then().then().then()
2. then会捕获未处理的异常然后把错误状态作为返回值返回,而done则会把异常直接抛出
二、finally()
参考:http://imweb.io/topic/57a0760393d9938132cc8da9

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值