Promise实战练习题

1.

setTimeout(function () {
    console.log(1)
}, 0);
 
new Promise(function executor(resolve) {
    console.log(2);
    for (var i = 0; i < 10000; i++) {
  	   i == 9999 && resolve();
    }
    console.log(3);
}).then(function () {
    console.log(4);
});

console.log(5);

/*
答案: 2,3,5,4,1
解析:
    1.先是同步, 执行new Promise() 
    2.进入循环,等到i == 9999 时执行resolve() 把.then(log(4))放到微任务中.
    3.循环执行完后,执行3
    4.继续执行同步的5
    5.同步执行完, 先执行微任务中的4, 在执行宏任务重的1
*/
    

2.

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

/*
答案: 1,2,4,3
解析: resolve()和reject()   都不会影响下面代码执行
*/

3.

setTimeout(() => {
    new Promise((resolve) => {
        resolve();
    }).then(() => {
        console.log(5);
    });
    console.log(4);
});

new Promise((resolve) => {
    resolve(); // 一旦调用了 resolve 就把后面的 then 对应的回调添加到了微任务队列
    console.log(1);
}).then(() => {
    console.log(3);
    // 执行 Promise.resolve() 又把后面的 then 添加到了微任务队列
    Promise.resolve().then(() => {
        console.log(6);
        
    }).then(() => {
        Promise.resolve().then(() => {
            console.log(7);
        });
    });
});

console.log(2);

/*
答案: 1,2,3,6,7,4,5
解析: 
    1.先把定时器放到宏任务中    
    2.执行new Promise() , 先调用resolve()把.then(放到微任务队列),打印1.  跳出 
    3.继续执行主流程,打印2
    4.主流程执行完毕, 执行微任务. 打印3, 
    继续执行resolve. 继续挂到微任务, 
    打印6, 继续挂到微任务, 打印7,微任务执行完毕. 执行宏任务
    5.执行setTimeout中的new Promise 调用resolve() 挂到微任务中,打印4, 执行完毕, 调用微任务打印5
*/

4.


// 定时器1
setTimeout(() => {
    new Promise((resolve) => {
        resolve();
    }).then(() => {
        console.log('5');
    });
    console.log(4);
    // 定时器2
    setTimeout(() => {
        Promise.resolve().then((res) => {
            console.log(666);
        });
    });
    Promise.resolve().then((res) => {
        console.log(888);
    });
});

new Promise((resolve) => {
    resolve();
    console.log(1);
}).then(() => {
    console.log(3);
    // 定时器3
    setTimeout(() => {
        Promise.resolve().then(() => {
            console.log('7');
        }).then(() => {
            Promise.resolve().then(() => {
                console.log('8');
            });
        });
    });
});
console.log(2);

/* 
    结果: 1,2,3,4,5,888,7,8,666
    解析:
    1.主流程先把setTimeout挂到宏任务中
    2.继续主流程,new Promise(), 调用resolve()把then()挂到微任务上,然后打印1
    3.继续主流程,打印2
    4.主流程结束,进入微任务, 打印3, 把定时器3挂到宏任务重,微任务结束,执行宏任务
    5.执行定时器1中的new Promise(),把5挂到微任务中. 然后打印4,再把定时器2挂到宏任务中,检查微任务,打印5,再打印888
    6.定时器1执行完毕, 执行定时器3, 先打印7, 再打印8
    7.再执行定时器2, 打印666
*/

5.

new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve({ test: 1 });
        resolve({ test: 2 });
        reject({ test: 2 });
    }, 1000);
}).then((data) => {
    console.log('result1', data);
}, (data1) => {
    console.log('result2', data1);
}).then((data) => {
    console.log('result3', data);
});

/*
结果: 
    result1 { test: 1 }
    result3 undefined

解析:
    创建了一个新的Promise对象。
    使用setTimeout来模拟异步操作,设置了1秒的延迟。
    在setTimeout的回调中,首先调用resolve({ test: 1 }),这会将Promise的状态改变为resolved,并设置解决值为{ test: 1 }。
    紧接着尝试再次调用resolve({ test: 2 }),但由于Promise状态已经固定为resolved,这个调用将被忽略。
    然后尝试调用reject({ test: 2 }),但同样地,由于Promise状态已经固定为resolved,这个调用也将被忽略。
    .then()方法接收两个参数,第一个是解决回调,第二个是拒绝回调。由于Promise已经解决,将执行第一个回调函数,打印result1 { test: 1 }。
    第一个.then()解决后,会返回一个新的解决状态的Promise(默认解决值为undefined,因为没有返回值),这会使得链中的下一个.then()被调用。
    第二个.then()没有提供参数,所以它接收到的值是undefined,并且由于没有提供回调函数,这里不会有任何打印操作。
*/

6.

new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log('1');
        reject({ test: 2 });
        console.log('2');
    }, 1000);
}).then((data) => {
    console.log('result1', data);
}).catch((e) => 
    new Promise((resolve) => { 
        resolve(123);
    })).then((data) => {
        console.log('result3-', data);
    }
);

/*
    答案: 1,2,result3-123
    解析: 
    创建了一个新的 Promise 对象,传递给它的执行器(executor)函数立即执行。
    setTimeout 是一个异步操作,它将在 1000 毫秒(1 秒)后执行其回调函数。
    当 setTimeout 的回调函数执行时,首先打印 1。
    然后调用 reject({ test: 2 }),这将使得 Promise 的状态从 pending(等待中)变为 rejected(已失败)。
    紧接着打印 2。在 reject 或 resolve 被调用之后,当前函数的剩余代码仍然会执行,但是 Promise 的状态已经被设置,不会因为后续操作而改变。
    第一个 .then 提供了一个成功的回调,但由于 Promise 被 reject 了,所以这个成功回调不会被调用。
    .catch 处理器捕获到了 Promise 的失败状态,并返回了一个新的 Promise(我们可以称之为 Promise2),这个新 Promise 是通过 new Promise((resolve) => { resolve(123); }) 创建的。
    Promise2 被立即 resolve 为 123,因为在其执行器函数中直接调用了 resolve(123)。
    第二个 .then 是在 Promise2 上注册的,它接收到的值是 123,因为上一个 .catch 返回了一个解析为 123 的 Promise。所以它打印 result3 123。
*/

7.

const first = () => (new Promise((resolve, reject) => {
    console.log(3);
    let p = new Promise((resolve, reject) => {
        console.log(7);
        setTimeout(() => {
            console.log(5);
            resolve(6);
        }, 0)
        resolve(1);
    });
    resolve(2);
    p.then((arg) => {
        console.log(arg);
    });

}));

first().then((arg) => {
    console.log(arg);
});
console.log(4);

/*
答案: 3,7,4,1,2,5
解析: 
第一轮事件循环,先执行宏任务,主script,new Promise立即执行,输出 3,执行p这个new Promise操作,输出 7,
发现setTimeout,将回调函数放入下一轮任务队列(Event Quene),p的then,暂且命名为then1,放入微任务队列,且first也有then,命名为then2,放入微任务队列。
执行console.log(4),输出 4,宏任务执行结束。
再执行微任务,执行then1,输出 1,执行then2,输出 2.
第一轮事件循环结束,开始执行第二轮。第二轮事件循环先执行宏任务里面的,也就是setTimeout的回调,输出 5.

重要: resolve(6)不会生效,因为p的Promise状态一旦改变就不会再变化了。
*/

8.

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('success')
  }, 1000)
})
const promise2 = promise1.then(() => {
  throw new Error('error!!!')
})

console.log('promise1', promise1)
console.log('promise2', promise2)

setTimeout(() => {
  console.log('promise1', promise1)
  console.log('promise2', promise2)
}, 2000)

/*
答案: 
同步打印
promise1 Promise { <pending> }
promise2 Promise { <pending> }
2秒后打印
promise1 Promise { 'success' }
promise2 Promise { <rejected> Error: error!!! }

promise2 并不是 promise1,而是返回的一个新的 Promise 实例。
*/

9.

const promise = new Promise((resolve, reject) => {
  resolve('success1')
  reject('error')
  resolve('success2')
})

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

  /*
  答案: then: success1
  重要: promise 状态一旦改变则不能再变。
  */

10.

Promise.resolve(1)
  .then((res) => {
    console.log(res)
    return 2
  })
  .catch((err) => {
    return 3
  })
  .then((res) => {
    console.log(res)
  })
  
/*
  答案: 1,2
  
  重要: promise 每次调用 .then 或者 .catch 都会返回一个新的 promise,从而实现了链式调用。
*/

11

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('once')
    resolve('success')
  }, 1000)
})

const start = Date.now()
promise.then((res) => {
  console.log(res, Date.now() - start)
})
promise.then((res) => {
  console.log(res, Date.now() - start)
})

/*
结果:
once
success 1005
success 1007

重要:
promise 的 .then 或者 .catch 可以被调用多次,但这里 Promise 构造函数只执行一次。
或者说 promise 内部状态一经改变,并且有了一个值,
那么后续每次调用 .then 或者 .catch 都会直接拿到该值。


*/

12.

Promise.resolve()
  .then(() => {
    return new Error('error!!!')
  })
  .then((res) => {
    console.log('then: ', res)
  })
  .catch((err) => {
    console.log('catch: ', err)
  })
  
/*

结果:
then:  Error: error!!!

解析:
.then 或者 .catch 中 return 一个 error 对象并不会抛出错误,所以不会被后续的 .catch 捕获,需要改成其中一种:
return Promise.reject(new Error('error!!!'))
throw new Error('error!!!')
重要:
因为返回任意一个非 promise 的值都会被包裹成 promise 对象,即 return new Error('error!!!') 等价于 return Promise.resolve(new Error('error!!!'))。

*/

13.

const promise = Promise.resolve()
  .then(() => {
    return promise
  })
promise.catch(console.error)


/*
解析:.then 或 .catch 返回的值不能是 promise 本身,否则会造成死循环。

运行结果:
TypeError: Chaining cycle detected for promise #<Promise>   promise检测到链接循环
*/

14.

Promise.resolve(1)
  .then(2)
  .then(Promise.resolve(3))
  .then(console.log)
  
/*
答案: 1

重要: .then()方法可以接受一个函数作为参数,并将上一个.then()的返回值传递给下一个.then()。
如果传给.then()的不是一个函数,而是一个非函数值,这个值会被忽略,但是Promise链中的值传递仍会继续。

解析:
Promise.resolve(1) 创建一个立即解决为1的Promise对象。
.then(2) 由于2不是一个函数,它会被忽略,但是解决值1会传递到链的下一个.then()。
.then(Promise.resolve(3)) 同样,这里传入的是一个Promise,而不是一个函数,所以这个Promise会被忽略,但是上一个.then()传递的解决值1会继续传递到链的下一个.then()。
.then(console.log) 这里传入了一个函数(console.log),它会接收到上一个.then()传递的值1,并将其打印出来。
*/

15.

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: error

解析:
.then 可以接收两个参数,第一个是处理成功的函数,第二个是处理错误的函数。
.catch 是 .then 第二个参数的简便写法,但是它们用法上有一点需要注意:
重要: .then 的第二个处理错误的函数捕获不了第一个处理成功的函数抛出的错误,而后续的 .catch 可以捕获之前的错误。

*/

16.

process.nextTick(() => {
  console.log('nextTick')
})
Promise.resolve()
  .then(() => {
    console.log('then')
  })
setImmediate(() => {
  console.log('setImmediate')
})
console.log('end')

/*
答案: end,nextTick,then,setImmediate
解析:
console.log('end'):这是同步代码,会立即执行。
Promise.resolve().then(callback):这是微任务,它会在当前事件循环迭代的微任务队列中执行。
process.nextTick(callback):这个函数的回调也是微任务,但是process.nextTick()有一个特殊的队列,它会在当前事件循环迭代的其他微任务之前执行。
setImmediate(callback):这个函数的回调是宏任务,将在下一个事件循环迭代的宏任务队列中执行。
重要: process.nextTick(callback):这个函数的回调也是微任务,但是process.nextTick()有一个特殊的队列,它会在当前事件循环迭代的其他微任务之前执行。
*/

一些总结:

1.resolve()和reject()   都不会影响下面代码执行
2.new Promise((resolve) => {
      resolve();
  }).then(() => {
      console.log('qq');
  });
  Promise.resolve().then((res) => { // 这种写法是上面的简写.then都是微任务
      console.log(888);
  });
3.函数默认返回 undefined,  return Promise.resolve(undefined) // 隐藏!!!
4.两个resolve时,后一个resolve不会生效,因为Promise状态一旦改变就不会再变化了。    
5.const promise = new Promise(...)
    promise.then((res) => {
      console.log(res)
    })
    promise.then((res) => {
      console.log(res)
    })
  promise 的 .then 或者 .catch 可以被调用多次,但这里 Promise 构造函数只执行一次。
6.只有这两种写法能被reject捕获
  return Promise.reject(new Error('error!!!'))
  throw new Error('error!!!')
  重要:
  因为返回任意一个非 promise 的值都会被包裹成 promise 对象,即 return new Error('error!!!') 等价于 return Promise.resolve(new Error('error!!!'))。
7. .then 或 .catch 返回的值不能是 promise 本身,否则会造成死循环。 报错.
8. .then()方法可以接受一个函数作为参数,并将上一个.then()的返回值传递给下一个.then()。
    如果传给.then()的不是一个函数,而是一个非函数值,这个值会被忽略,但是Promise链中的值传递仍会继续。
9. .then 的第二个处理错误的函数捕获不了第一个处理成功的函数抛出的错误,而后续的 .catch 可以捕获之前的错误。
  

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值