Promise 学习

119 阅读2分钟

试题

1、执行顺序

const promise = new Promise((resolve, reject) => {
    console.log(1)
    resolve()
    console.log(2)
})
promise.then(() => {
    console.log(3)
})
console.log(4)

解析:
Promise 新建后就会立即执行。
new Promise构造函数是同步执行的。故先打印1,2;then是异步执行的,故先打印4,然后才打印3。
结果:1243

扩展

const promise = new Promise((resolve, reject) => {
  console.log(1);
  resolve(5);
  console.log(2);
}).then(val => {
  console.log(val);
});
promise.then(() => {
  console.log(3);
});
console.log(4);
setTimeout(function() {
  console.log(6);
});

解析:promise是微观任务,setTimeout是宏观任务,先执行微观任务,再执行宏观任务;微观任务里,先执行同步再执行异步。这里的微任务队列为:先添加的promise.resolve(5).then((val)=>{console.log(val)}),后添加的promise.then(() => { console.log(3)};
结果:124536

2、执行顺序

const first = () => (new Promise((resolve, reject) => {
    console.log(3); //3
    let p = new Promise((resolve, reject) => {
        console.log(7); //37
        setTimeout(() => { //放入下一轮队列
            console.log(5);
            resolve(6);
        }, 0)
        resolve(1); 
    });
    resolve(2);  
    p.then((arg) => { //then1 放入微任务队列 arg = 1 
        console.log(arg);
    });
}));

first().then((arg) => { //then2 放入微任务队列 arg = 2
    console.log(arg);
});
console.log(4); //374

//执行微任务队列then1,得到3741,执行then2,得到37412,执行下一队列中的setTimeout,得到374125

结果:374125

3、resolve和reject

const promise = new Promise((resolve, reject) => {
  resolve('success1') //  pending->fulfilled, 状态一旦改变不能再改
  reject('error')
  resolve('success2')
})

promise
  .then((res) => {
    console.log('then: ', res) // then: success1
  })
  .catch((err) => {
    console.log('catch: ', err)
  })

4、then和catch

Promise.resolve(1)
  .then((res) => {
    console.log(res) //1
    return 2
  })
  .catch((err) => {
    return 3
  })
  .then((res) => {
    console.log(res) //链式调用 //2
  })

5、then和catch

Promise.resolve()
  .then(() => {
    return new Error('error!!!') //等价于 return Promise.resolve(new Error('error!!!'))
  })
  .then((res) => {
    console.log('then: ', res) // then:  Error: error!!! at <anonymous>
  })
  .catch((err) => {
    console.log('catch: ', err)
  })

解析:then 或者 catch 中 return 一个 error 对象并不会抛出错误,所以不会被后续的 .catch 捕获。可以使用以下方式被catch捕获。

return Promise.reject(new Error('error!!!'))
//或者
throw new Error('error!!!')

6、死循环

const promise = Promise.resolve()
  .then(() => {
    return promise
  })
promise.catch(console.error)
// TypeError: Chaining cycle detected for promise #<Promise>

7、值穿透

Promise.resolve(1)
  .then(2)
  .then(Promise.resolve(3))
  .then(console.log) //“1”穿透上面两个then(Promise),到达这里成为实参

解析:then 或者catch 的参数期望是函数,传入非函数则会发生值穿透。

Promise.resolve(1).then(Promise.resolve(2)).then((v) => {
  console.log(v)
}) // 1

Promise.resolve(1).then(return Promise.resolve(2)).then((v) => {
  console.log(v)
}) //Uncaught SyntaxError: Unexpected token return;

Promise.resolve(1).then(null).then((v) => {
  console.log(v)
})// 1

Promise.resolve(1).then(return 2).then((v) => {
  console.log(v)
})// Uncaught SyntaxError: Unexpected token return;

Promise.resolve(1).then(() => {
  return 2
}).then((v) => {
  console.log(v) // 2
})

8、捕获错误

Promise.resolve()
  .then(function success (res) {
    throw new Error('error')
  }, function fail1 (e) {
    console.error('fail1: ', e)
  })
  .catch(function fail2 (e) {
    console.error('fail2: ', e) // fail2: Error
  })

解析:then有两个参数,写法为then(function(resolve){}, function(reject){}),catch是then的第二个参数的简写。注意:同一个then中第二个参数无法捕获第一个参数抛出的错误。

//上面例子写法等价于
Promise.resolve()
  .then(function success1 (res) {
    throw new Error('error')
  }, function fail1 (e) {
    console.error('fail1: ', e)
  })
  .then(function success2 (res) {
  }, function fail2 (e) {
    console.error('fail2: ', e)
  })