Promise的常见问题
1、Promise解决了些什么问题
2、Promise在事件循环机制中的执行过程是怎样的
3、Promise常用的API有哪些
4、手写一个符合 Promise/A+ 规范的 Promise
1、Promise解决了些什么问题
在promise出现之前,想要拿到回调结果就必须得使用嵌套的方式,而且每一个任务处理都会有两种结果需要处理(失败和成功),这就是所谓的回调地狱,在代码维护上很艰难
let fs = require('fs')
fs.readFile('./name.txt','utf8',function(err,data){
fs.readFile(data, 'utf8',function(err,data){
fs.readFile(data,'utf8',function(err,data){
console.log(data);
})
})
})
(1)**解决了嵌套的问题,**把第一个函数的输出作为下一个函数的输入,使用链式调用
(2)合并了多个任务的结果处理,.catch方法不管是上面哪个任务出现了异常都会进入到catch当中
2、Promise在事件循环机制中的执行过程是怎样的(链接)
3、Promise的常用api
(1)对象方法
Promise.all()并发处理多个异步任务,所有任务都执行完成才能得到结果。
Promise.race()并发处理多个异步任务,只要有一个任务完成就能得到结果。
(2)实例方法
.then 得到异步任务的正确结果
.catch 获取异常信息
.finally 成功与失败都会执行
4、手写一个符合 Promise/A+ 规范的 Promise(原链接)
(1)then 的参数 onFulfilled 和 onRejected 可以缺省,如果 onFulfilled 或者 onRejected不是函数,将其忽略,且依旧可以在下面的 then 中获取到之前返回的值;「规范 Promise/A+ 2.2.1、2.2.1.1、2.2.1.2」
(2)promise 可以 then 多次,每次执行完 promise.then 方法后返回的都是一个“新的promise";「规范 Promise/A+ 2.2.7」
(3)如果 then 的返回值 x 是一个普通值,那么就会把这个结果作为参数,传递给下一个 then 的成功的回调中;
(4)如果 then 中抛出了异常,那么就会把这个异常作为参数,传递给下一个 then 的失败的回调中;「规范 Promise/A+ 2.2.7.2」
(5)如果 then 的返回值 x 是一个 promise,那么会等这个 promise 执行完,promise 如果成功,就走下一个 then 的成功;如果失败,就走下一个 then 的失败;如果抛出异常,就走下一个 then 的失败;「规范 Promise/A+ 2.2.7.3、2.2.7.4」
(6)如果 then 的返回值 x 和 promise 是同一个引用对象,造成循环引用,则抛出异常,把异常传递给下一个 then 的失败的回调中;「规范 Promise/A+ 2.3.1」
(7)如果 then 的返回值 x 是一个 promise,且 x 同时调用 resolve 函数和 reject 函数,则第一次调用优先,其他所有调用被忽略;「规范 Promise/A+ 2.3.3.3.3」
看几个promise的例子
第一题:第1秒红灯亮,第2秒黄灯亮,第3秒蓝灯亮;如何让三个灯不断交替重复亮灯?(用Promise实现)
function red() {
console.log("red");
}
function green() {
console.log("green");
}
function yellow() {
console.log("yellow");
}
const light = function (timer, cb) {
return new Promise(resolve => {
setTimeout(() => {
cb()
resolve()
}, timer)
})
}
const step = function () {
Promise.resolve().then(() => {
return light(3000, red)
}).then(() => {
return light(2000, green)
}).then(() => {
return light(1000, yellow)
}).then(() => {
return step()
})
}
step();
light 方法使用setTimeout做延时使用promise包裹的原因是,setTimeout属于一个宏任务,宏任务会交给其他延时线程处理然后加入到消息队列当中去,给事件循环机制来处理,如果在then方法中不return一个promise的而且什么都不return或者随便return一个值的话就会发生值的穿透,不会等延时执行完毕再去执行下一个then当中的内容。
这个题可以使用async和await来简洁一下
function light(color,delay){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log(color);
resolve();
},delay)
})
}
function async loop(){
await light("red",1000);
await light("yellow",1000);
await light("green",1000);
loop();
}
loop()
第二题:使用Promise实现每隔1秒输出1,2,3
let arr = [1,2,3];
arr.reduce((pre,item)=>{
return pre.then(()=>{
return new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log(item)
resolve()
},1000)
})
})
},Promise.resolve())
这里的reduce的使用方式:
arr.reduce(callback,[initialValue])
callback (执行数组中每个值的函数,包含四个参数)
1、previousValue (上一次调用回调返回的值,或者是提供的初始值(initialValue))
2、currentValue (数组中当前被处理的元素)
3、index (当前元素在数组中的索引)
4、array (调用 reduce 的数组)
initialValue (作为第一次调用 callback 的第一个参数。)