1. promise
📢注意:
new Promise不是微任务!当调用Promise.resolve()或者Promise.reject()才会产生微任务。new Promise的返回值是状态。- 刚开始整个脚本作为第一次宏任务来执行。
Promise构造函数中的resolve或reject只有第一次执行有效。
总结:
Promise的状态一经改变就不能再改变。.then和.catch都会返回一个新的Promise。catch不管被连接到哪里,都能捕获上层未捕捉过的错误。- 在
Promise中,返回任意一个非promise的值都会被包裹成promise对象,例如return 2会被包装为return Promise.resolve(2);return new Error('error!!!')会在then中被包裹成return Promise.resolve(new Error('error!!!'))。 Promise的.then或者.catch可以被调用多次,但如果Promise内部的状态一经改变,并且有了一个值,那么后续每次调用.then或者.catch的时候都会直接拿到该值。.then或者.catch中return一个error对象并不会抛出错误,所以不会被后续的.catch捕获。.then或.catch返回的值不能是promise本身,否则会造成死循环。.then或者.catch的参数期望是函数,传入非函数则会发生值透传。.then方法是能接收两个参数的,第一个是处理成功的函数,第二个是处理失败的函数,在某些时候可以认为catch是.then第二个参数的简便写法。.finally方法也是返回一个Promise,它在Promise结束的时候,无论结果为resolved还是rejected,都会执行里面的回调函数。- 如果要抛出一个错误,可以用
return Promise.reject(new Error('error!!!'))或者throw new Error('error!!!')。
.finally():
.finally()方法不管Promise对象最后的状态如何都会执行。.finally()方法的回调函数不接受任何的参数,也就是说在.finally()函数中是没办法知道Promise最终的状态是resolved还是rejected。.finally()方法最终返回的默认会是一个上一次的Promise对象值,不过如果抛出的是一个异常则返回异常的Promise对象。
Promise.all()作用:接收一组异步任务,然后并行执行异步任务,并且在所有异步操作执行完成后才执行回调。Promise.race()作用:接收一组异步任务,然后并行执行异步任务,只保留第一个执行完成的异步操作的结果,其他的方法仍在执行,不过执行结果会被抛弃。
如果在async函数中抛出了错误,则终止错误结果,不会继续向下执行。
1.1 求输出
console.log(1);setTimeout(() => {console.log(2)}, 1000)async function fn() {console.log(3);setTimeout(() => {console.log(4)}, 20)return Promise.reject();}async function run() {console.log(5);await fn();console.log(6);}run()//for循环执行约150msfor(let i = 0; i<90000000; i++) {}setTimeout(() => {console.log(7);new Promise(resolve => {console.log(8);resolve();}).then(() => {console.log(9);})}, 0)console.log(10)
1.2 求输出
async function async1() {console.log("async1 start");await async2();console.log("async1 end");}async function async2() {console.log("async2");}console.log("script start");setTimeout(function() {console.log("setTimeout");}, 0);async1();new Promise(resolve => {console.log("promise1");resolve();}).then(function() {console.log("promise2");});console.log('script end')// 答案script startasync1 startasync2promise1script endasync1 endpromise2setTimeout
1.3 异步加法
// 假设有一台本地机器,无法做加减乘除运算(包括位运算)。// 因此无法执行 a + b、a+ = 1 这样的 JS 代码。// 然后我们提供一个服务器端的 HTTP API。// 可以传两个数字类型的参数,响应结果是这两个参数的和。// 这个 HTTP API 的 JS SDK(在本地机器上运行)的使用方法如下:// SDK 的模拟实现:function asyncAdd(a, b, cb) {setTimeout(() => {cb(null, a + b);}, Math.floor(Math.random()*1000))}// SDK 模拟调用asyncAdd(3, 5, (err, result) => {console.log(result); // 8});async function sum(...args) {if (args.length < 2) return args[0] || 0;if (args.length === 2) return await asyncAdd(args[0], args[1]);const len = args.length;const half = (len >> 1);const left = await sum(...args.slice(0, half + 1));const right = await sum(...args.slice(half + 1));res = asyncAdd(left, right);// let res = args[0];// for (let i = 1; i < args.length; i++) {// res = await asyncAdd(sum, args[i]);// }return res;}// 现在要求在本地机器上实现一个 sum 函数,支持以下用法:(async () => {const result1 = await sum(1, 4, 6, 9, 2, 4);const result2 = await sum(3, 4, 9, 2, 5, 3, 2, 1, 7);const result3 = await sum(1, 6, 0, 5);console.log([result1, result2, result3]); // [26, 36, 12]})();
完整解法
function asyncAdd(a, b, cb) {setTimeout(() => {cb(null, a + b);}, Math.floor(Math.random()*100))}function sum(...args) {const result = []function _sum(resolve, reject) {new Promise((r, j) => {let a = args.pop()let b = args.pop()a = a !== undefined? a : 0b = b !== undefined? b : 0 // 如果访问的元素超出了数组范围,则转为 0asyncAdd(a, b, (err, res) => {if (err) j(err)r(res)})if (args.length) {_sum(resolve, reject)}}).then(val => {result.push(val)setTimeout(() => {if (args.length <= 0) {resolve(sum(...result))}}, 100)})}return new Promise((resolve, reject) => {if (!args || !args.length) resolve(0)if (args.length == 1) resolve(args[0])_sum(resolve, reject)})}(async () => {const result1 = await sum(1, 4, 6, 9, 1, 4)const result2 = await sum(3, 4, 9, 2, 5, 3, 2, 1, 7)const result3 = await sum(1, 6, 0, 5)console.log([result1, result2, result3]) // [25, 36, 12]})()
1.4 输出
const promise = new Promise((resolve, reject) => {console.log(1);resolve();console.log(2);})promise.then(() => {console.log(3);})console.log(4);
1.5 输出
console.log(1)setTimeout(() => {console.log(2)}, 0)async function echo() {console.log(5)await Promise.resolve()console.log(6)}echo()requestAnimationFrame(() => {console.log(8)})new Promise((resolve) => {console.log(3)resolve()}).then(() => {console.log(4)})console.log(7)1 5 3 7 6 4 8 2
1.6 输出
// 看代码说结果setTimeout(function() {console.log('setTimeout1');new Promise(function(resolve) {console.log('promise0');resolve()}).then(function() {console.log('settimeout promise resolveed');})});setTimeout(function() {console.log('setTimeout2');});const P = new Promise(function(resolve) {console.log('promise');for (var i = 0; i < 10000; i++) {if(i === 10) {console.log('for');}if (i === 9999) {resolve('resolve');}}}).then(function(val) {console.log('resolve1');}).then(function(val) {console.log('resolve2');});new Promise(function(resolve) {console.log('promise2');resolve('resolve');}).then(function(val) {console.log('resolve3');})console.log('console');
1.7 判断打印结果
setTimeout(()=>{console.log(1);},0);async function hello(){console.log(2);new Promise((resolve)=>{console.log(9)resolve();console.log(3);}).then(function(){console.log(10);})}hello()new Promise((resolve,reject)=>{console.log(4)resolve();console.log(5)}).then(console.log(6)).catch(console.log(7))console.log(8)// 判断打印结果
1.8 判断打印结果
const pro = new Promise((resolve, reject) => {const innerpro = new Promise((resolve, reject) => {setTimeout(() => {resolve(1);}, 0);console.log(2);resolve(3);});innerpro.then(res => console.log(res));resolve(4);console.log("pro");})pro.then(res => console.log(res));console.log("end");//2//pro//end//3//4
1.9 编程题
由于当前环境下没有本地实现的加法函数,加法是通过异步 api 实现的,一次只支持两个数字参数,要求实现一个加法函数支持多个参数,要求最快的计算效率。
const addRemote = async (a: number, b: number) =>new Promise((resolve) => {setTimeout(() => resolve(a + b), 1000);});// version 1.0async function add_v1(...inputs: number[]) {let handler = Promise.resolve(inputs[0]);for (let i = 1; i < inputs.length; i++) {handler = handler.then((res) => {return addRemote(res, input[i]).then((res) => {return res;});});}await handler.then((res) => {return res;});}// version 2.0async function add_v2(...inputs: number[]) {if (inputs.length === 1) {console.log(inputs[0]);return inputs[0];}let tasks = [];let i = 0;for (; i < inputs.length; i += 2) {tasks.push(addRemote(inputs[i], inputs[i + 1]));}let handler = Promise.all(tasks);let res = await handler.then((res) => {return add_v2(...([...res, ...inputs.slice(i + 1)] as number[]));});return res;}add_v2(1, 2, 3, 4).then((res) => {console.log(res);});
1.10
async function async1() {console.log('async1 start');await async2();console.log('async1 end');}async function async2() {console.log('async2 start');return new Promise((resolve, reject) => {resolve();console.log('async2 promise');})}console.log('script start');setTimeout(function() {console.log('setTimeout');}, 0);async1();new Promise(function(resolve) {console.log('promise1');resolve();}).then(function() {console.log('promise2');}).then(function() {console.log('promise3');});console.log('script end');
