1. promise

📢注意:

  1. new Promise不是微任务!当调用Promise.resolve()或者Promise.reject()才会产生微任务。
  2. new Promise的返回值是状态。
  3. 刚开始整个脚本作为第一次宏任务来执行。
  4. Promise构造函数中的resolvereject只有第一次执行有效。

总结:

  1. Promise的状态一经改变就不能再改变。
  2. .then.catch都会返回一个新的Promise
  3. catch不管被连接到哪里,都能捕获上层未捕捉过的错误。
  4. Promise中,返回任意一个非promise的值都会被包裹成promise对象,例如return 2会被包装为return Promise.resolve(2)return new Error('error!!!')会在then中被包裹成return Promise.resolve(new Error('error!!!'))
  5. Promise.then或者.catch可以被调用多次,但如果Promise内部的状态一经改变,并且有了一个值,那么后续每次调用.then或者.catch的时候都会直接拿到该值。
  6. .then或者.catchreturn一个error对象并不会抛出错误,所以不会被后续的.catch捕获。
  7. .then.catch返回的值不能是promise本身,否则会造成死循环。
  8. .then或者.catch的参数期望是函数,传入非函数则会发生值透传。
  9. .then方法是能接收两个参数的,第一个是处理成功的函数,第二个是处理失败的函数,在某些时候可以认为catch.then第二个参数的简便写法。
  10. .finally方法也是返回一个Promise,它在Promise结束的时候,无论结果为resolved还是rejected,都会执行里面的回调函数。
  11. 如果要抛出一个错误,可以用return Promise.reject(new Error('error!!!'))或者throw new Error('error!!!')

.finally()

  1. .finally()方法不管Promise对象最后的状态如何都会执行。
  2. .finally()方法的回调函数不接受任何的参数,也就是说在.finally()函数中是没办法知道Promise最终的状态是resolved还是rejected
  3. .finally()方法最终返回的默认会是一个上一次的Promise对象值,不过如果抛出的是一个异常则返回异常的Promise对象。

Promise.all()作用:接收一组异步任务,然后并行执行异步任务,并且在所有异步操作执行完成后才执行回调。
Promise.race()作用:接收一组异步任务,然后并行执行异步任务,只保留第一个执行完成的异步操作的结果,其他的方法仍在执行,不过执行结果会被抛弃。
如果在async函数中抛出了错误,则终止错误结果,不会继续向下执行。

1.1 求输出

  1. console.log(1);
  2. setTimeout(() => {console.log(2)}, 1000)
  3. async function fn() {
  4. console.log(3);
  5. setTimeout(() => {console.log(4)}, 20)
  6. return Promise.reject();
  7. }
  8. async function run() {
  9. console.log(5);
  10. await fn();
  11. console.log(6);
  12. }
  13. run()
  14. //for循环执行约150ms
  15. for(let i = 0; i<90000000; i++) {}
  16. setTimeout(() => {
  17. console.log(7);
  18. new Promise(resolve => {
  19. console.log(8);
  20. resolve();
  21. }).then(() => {
  22. console.log(9);
  23. })
  24. }, 0)
  25. console.log(10)

1.2 求输出

  1. async function async1() {
  2. console.log("async1 start");
  3. await async2();
  4. console.log("async1 end");
  5. }
  6. async function async2() {
  7. console.log("async2");
  8. }
  9. console.log("script start");
  10. setTimeout(function() {
  11. console.log("setTimeout");
  12. }, 0);
  13. async1();
  14. new Promise(resolve => {
  15. console.log("promise1");
  16. resolve();
  17. }).then(function() {
  18. console.log("promise2");
  19. });
  20. console.log('script end')
  21. // 答案
  22. script start
  23. async1 start
  24. async2
  25. promise1
  26. script end
  27. async1 end
  28. promise2
  29. setTimeout

1.3 异步加法

  1. // 假设有一台本地机器,无法做加减乘除运算(包括位运算)。
  2. // 因此无法执行 a + b、a+ = 1 这样的 JS 代码。
  3. // 然后我们提供一个服务器端的 HTTP API。
  4. // 可以传两个数字类型的参数,响应结果是这两个参数的和。
  5. // 这个 HTTP API 的 JS SDK(在本地机器上运行)的使用方法如下:
  6. // SDK 的模拟实现:
  7. function asyncAdd(a, b, cb) {
  8. setTimeout(() => {
  9. cb(null, a + b);
  10. }, Math.floor(Math.random()*1000))
  11. }
  12. // SDK 模拟调用
  13. asyncAdd(3, 5, (err, result) => {
  14. console.log(result); // 8
  15. });
  16. async function sum(...args) {
  17. if (args.length < 2) return args[0] || 0;
  18. if (args.length === 2) return await asyncAdd(args[0], args[1]);
  19. const len = args.length;
  20. const half = (len >> 1);
  21. const left = await sum(...args.slice(0, half + 1));
  22. const right = await sum(...args.slice(half + 1));
  23. res = asyncAdd(left, right);
  24. // let res = args[0];
  25. // for (let i = 1; i < args.length; i++) {
  26. // res = await asyncAdd(sum, args[i]);
  27. // }
  28. return res;
  29. }
  30. // 现在要求在本地机器上实现一个 sum 函数,支持以下用法:
  31. (async () => {
  32. const result1 = await sum(1, 4, 6, 9, 2, 4);
  33. const result2 = await sum(3, 4, 9, 2, 5, 3, 2, 1, 7);
  34. const result3 = await sum(1, 6, 0, 5);
  35. console.log([result1, result2, result3]); // [26, 36, 12]
  36. })();

完整解法

  1. function asyncAdd(a, b, cb) {
  2. setTimeout(() => {
  3. cb(null, a + b);
  4. }, Math.floor(Math.random()*100))
  5. }
  6. function sum(...args) {
  7. const result = []
  8. function _sum(resolve, reject) {
  9. new Promise((r, j) => {
  10. let a = args.pop()
  11. let b = args.pop()
  12. a = a !== undefined? a : 0
  13. b = b !== undefined? b : 0 // 如果访问的元素超出了数组范围,则转为 0
  14. asyncAdd(a, b, (err, res) => {
  15. if (err) j(err)
  16. r(res)
  17. })
  18. if (args.length) {
  19. _sum(resolve, reject)
  20. }
  21. })
  22. .then(val => {
  23. result.push(val)
  24. setTimeout(() => {
  25. if (args.length <= 0) {
  26. resolve(sum(...result))
  27. }
  28. }, 100)
  29. })
  30. }
  31. return new Promise((resolve, reject) => {
  32. if (!args || !args.length) resolve(0)
  33. if (args.length == 1) resolve(args[0])
  34. _sum(resolve, reject)
  35. })
  36. }
  37. (async () => {
  38. const result1 = await sum(1, 4, 6, 9, 1, 4)
  39. const result2 = await sum(3, 4, 9, 2, 5, 3, 2, 1, 7)
  40. const result3 = await sum(1, 6, 0, 5)
  41. console.log([result1, result2, result3]) // [25, 36, 12]
  42. })()

1.4 输出

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

1.5 输出

  1. console.log(1)
  2. setTimeout(() => {
  3. console.log(2)
  4. }, 0)
  5. async function echo() {
  6. console.log(5)
  7. await Promise.resolve()
  8. console.log(6)
  9. }
  10. echo()
  11. requestAnimationFrame(() => {
  12. console.log(8)
  13. })
  14. new Promise((resolve) => {
  15. console.log(3)
  16. resolve()
  17. }).then(() => {
  18. console.log(4)
  19. })
  20. console.log(7)
  21. 1 5 3 7 6 4 8 2

1.6 输出

  1. // 看代码说结果
  2. setTimeout(function() {
  3. console.log('setTimeout1');
  4. new Promise(function(resolve) {
  5. console.log('promise0');
  6. resolve()
  7. }).then(function() {
  8. console.log('settimeout promise resolveed');
  9. })
  10. });
  11. setTimeout(function() {
  12. console.log('setTimeout2');
  13. });
  14. const P = new Promise(function(resolve) {
  15. console.log('promise');
  16. for (var i = 0; i < 10000; i++) {
  17. if(i === 10) {
  18. console.log('for');
  19. }
  20. if (i === 9999) {
  21. resolve('resolve');
  22. }
  23. }
  24. }).then(function(val) {
  25. console.log('resolve1');
  26. }).then(function(val) {
  27. console.log('resolve2');
  28. });
  29. new Promise(function(resolve) {
  30. console.log('promise2');
  31. resolve('resolve');
  32. }).then(function(val) {
  33. console.log('resolve3');
  34. })
  35. console.log('console');

1.7 判断打印结果

  1. setTimeout(()=>{
  2. console.log(1);
  3. }
  4. ,0);
  5. async function hello(){
  6. console.log(2);
  7. new Promise((resolve)=>{
  8. console.log(9)
  9. resolve();
  10. console.log(3);
  11. }).then(function(){
  12. console.log(10);
  13. })
  14. }
  15. hello()
  16. new Promise((resolve,reject)=>{
  17. console.log(4)
  18. resolve();
  19. console.log(5)
  20. }).then(console.log(6)).catch(console.log(7))
  21. console.log(8)
  22. // 判断打印结果

1.8 判断打印结果

  1. const pro = new Promise((resolve, reject) => {
  2. const innerpro = new Promise((resolve, reject) => {
  3. setTimeout(() => {
  4. resolve(1);
  5. }, 0);
  6. console.log(2);
  7. resolve(3);
  8. });
  9. innerpro.then(res => console.log(res));
  10. resolve(4);
  11. console.log("pro");
  12. })
  13. pro.then(res => console.log(res));
  14. console.log("end");
  15. //2
  16. //pro
  17. //end
  18. //3
  19. //4

1.9 编程题

由于当前环境下没有本地实现的加法函数,加法是通过异步 api 实现的,一次只支持两个数字参数,要求实现一个加法函数支持多个参数,要求最快的计算效率。

  1. const addRemote = async (a: number, b: number) =>
  2. new Promise((resolve) => {
  3. setTimeout(() => resolve(a + b), 1000);
  4. });
  5. // version 1.0
  6. async function add_v1(...inputs: number[]) {
  7. let handler = Promise.resolve(inputs[0]);
  8. for (let i = 1; i < inputs.length; i++) {
  9. handler = handler.then((res) => {
  10. return addRemote(res, input[i]).then((res) => {
  11. return res;
  12. });
  13. });
  14. }
  15. await handler.then((res) => {
  16. return res;
  17. });
  18. }
  19. // version 2.0
  20. async function add_v2(...inputs: number[]) {
  21. if (inputs.length === 1) {
  22. console.log(inputs[0]);
  23. return inputs[0];
  24. }
  25. let tasks = [];
  26. let i = 0;
  27. for (; i < inputs.length; i += 2) {
  28. tasks.push(addRemote(inputs[i], inputs[i + 1]));
  29. }
  30. let handler = Promise.all(tasks);
  31. let res = await handler.then((res) => {
  32. return add_v2(...([...res, ...inputs.slice(i + 1)] as number[]));
  33. });
  34. return res;
  35. }
  36. add_v2(1, 2, 3, 4).then((res) => {
  37. console.log(res);
  38. });

1.10

  1. async function async1() {
  2. console.log('async1 start');
  3. await async2();
  4. console.log('async1 end');
  5. }
  6. async function async2() {
  7. console.log('async2 start');
  8. return new Promise((resolve, reject) => {
  9. resolve();
  10. console.log('async2 promise');
  11. })
  12. }
  13. console.log('script start');
  14. setTimeout(function() {
  15. console.log('setTimeout');
  16. }, 0);
  17. async1();
  18. new Promise(function(resolve) {
  19. console.log('promise1');
  20. resolve();
  21. }).then(function() {
  22. console.log('promise2');
  23. }).then(function() {
  24. console.log('promise3');
  25. });
  26. console.log('script end');