尼采般地抒情

尼采般地抒情

尼采般地抒情

音乐盒

站点信息

文章总数目: 309
已运行时间: 1338

一、JS代码执行机制

JavaScript的单线程

单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。这样所导致的问题是: 如果 JS 执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。

同步任务和异步任务

单线程导致的问题就是后面的任务等待前面任务完成,如果前面任务很耗时(比如读取网络数据),后面任务不得不一直等待!!

为了解决这个问题,利用多核 CPU 的计算能力,HTML5 提出 Web Worker 标准,允许 JavaScript 脚本创建多个线程,但是子线程完全受主线程控制。于是,JS 中出现了同步任务异步任务


JS中所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。

  • 【同步任务】指的是:在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;
  • 【异步任务】指的是:不进入主线程、而进入“任务队列”的任务,当主线程中的任务运行完了,才会将异步任务相关的回调函数从”任务队列”取出异步任务放入主线程执行。

异步任务又分为宏任务和微任务

宏任务

  • 主代码块
  • setTimeout
  • setInterval

微任务

  • process.nextTick ()
  • Promise
  • Object.observe

事件循环机制

  1. 碰到同步任务,就先执行执行栈中的同步任务

遇到函数的嵌套调用就把函数压入栈内再依次“剥洋葱”

  1. 碰到异步任务就压入任务队列(异步任务分为宏任务和微任务)
  2. 当前执行栈中的所有同步任务执行完毕,就将执行异步任务,异步任务执行原则“先微后宏”

由于主线程不断地重复获得任务、执行任务、再获取任务、再执行……,这种机制被称为事件循环(Event Loop)

实例

const promise = new Promise((resolve, reject) => {
  // new 先行
  console.log(1);
  resolve("success");
  console.log(2);
});
promise.then((data) => {
  // 微任务
  console.log(data);
  console.log(3);
});
console.log(4);
1
2
4
success
3
const promise1 = new Promise((resolve, reject) => {
  console.log("promise1");
  resolve("resolve1");
});
const promise2 = promise1.then((res) => {
  console.log(res);
});
console.log("1", promise1);
console.log("2", promise2);
promise1
1 Promise { 'resolve1' }
2 Promise { <pending> }
resolve1
测试代码
// setTimeout(()=>{
//     console.log(1)
//   },0)
// new Promise((resolve) =>{
//     console.log(2)
//     resolve()
//   }).then(()=>{ // 此时将then的内容放到微任务队列,然后执行同步代码 5
//     console.log(3)
//   }).then(()=>{
//     console.log(4)
//   })
//   console.log(5)

// setTimeout(() => {
//     console.log('timer1');
//     setTimeout(() => {
//       console.log('timer3')
//     }, 0)
//   }, 0)
// setTimeout(() => {
//     console.log('timer2')
//   }, 0)
// console.log('start')

// setTimeout(() => {
//     console.log('timer1');
//     Promise.resolve().then(() => {
//       console.log('promise')
//     })
//   }, 0)
// setTimeout(() => {
//     console.log('timer2')
//   }, 0)
// console.log('start')

// 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) // 在1 2 之前执行,此时1 2都在微任务队列里面

// setTimeout(() => {
//     console.log("0")
//   }, 0)

// new Promise((resolve,reject)=>{
//     console.log("1")
//     resolve()
//   }).then(()=>{ // then碰到then,就将其全部放到微任务队列,再细致考虑
//     console.log("2")
//     new Promise((resolve,reject)=>{
//       console.log("3")
//       resolve()
//     }).then(()=>{
//       console.log("4") // 先5后4 “队列”
//     }).then(()=>{
//       console.log("5")
//     })
//   }).then(()=>{
//     console.log("6")
//   })

// new Promise((resolve,reject)=>{
//     console.log("7")
//     resolve() //2
//   }).then(()=>{
//     console.log("8")
//   })

// Promise.resolve().then(() => {
//     console.log('promise1');
//     const timer2 = setTimeout(() => {
//       console.log('timer2')
//     }, 0)
//   });

// const timer1 = setTimeout(() => {
//     console.log('timer1')
//     Promise.resolve().then(() => {
//       console.log('promise2')
//     })
//   }, 0)

// console.log('start');

// 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)

异步编程

Promise

  • 理解并能准确判断代码执行时机
测试代码
/**
 * Promise:resolve reject then catch finally
 */
// let p1 = new Promise((resolve, reject) => {
//     setTimeout(() => {
//       resolve('success')
//     },1000)
//   })
  
//   let p2 = new Promise((resolve, reject) => {
//     setTimeout(() => {
//       reject('failed')
//     }, 500)
//   })
  
//   Promise.race([p1, p2]).then((result) => {
//     console.log(result)
//   }).catch((error) => {
//     console.log(error)  // 打开的是 'failed'
// })

// function test(resolve, reject) {
//   let timeOut = Math.random() * 2;
//   console.log('set timeout to: ' + timeOut + ' seconds.');
//   setTimeout(function () {
//       if (timeOut < 1) {
//         console.log('call resolve()...');
//         resolve('200 OK');
//       }
//       else {
//         console.log('call reject()...');
//         reject('timeout in ' + timeOut + ' seconds.');
//       }
//   }, timeOut * 1000);
// }

// let p1 = new Promise(test);
// let p2 = p1.then(function (result) {
//     console.log('成功:' + result);
// });
// let p3 = p2.catch(function (reason) {
//     console.log('失败:' + reason);
// });

// function test(resolve, reject) {
//   let timeOut = Math.random() * 2;
//   console.log('set timeout to: ' + timeOut + ' seconds.');
//   setTimeout(function () {
//       if (timeOut < 1) {
//         console.log('call resolve()...');
//         resolve('200 OK');
//       }
//       else {
//         console.log('call reject()...');
//         reject('timeout in ' + timeOut + ' seconds.');
//       }
//   }, timeOut * 1000);
// }

// new Promise(test)
// .then(function (result) {
//   console.log('成功:' + result);
// })
// .catch(function (reason) {
//   console.log('失败:' + reason);
// })

// const promise = new Promise((resolve, reject) => {
//     reject("error");
//     resolve("success2"); // 需要return才能传递结果
//   });
//   promise.then(res => {
//       console.log("then1: ", res); // 需要return才能往下传递结果
//   }).then(res => {
//       console.log("then2: ", res);
//   }).catch(err => {
//       console.log("catch: ", err);
//   }).then(res => {
//       console.log("then3: ", res); // undefined catch也会返回promise对象
//   })

// Promise.resolve(1)
//   .then(res => {
//     console.log(res);
//     return 2; // return 2会被包装成resolve(2)
//   })
//   .catch(err => {
//     return 3;
//   })
//   .then(res => {
//     console.log(res);
//   });

// const promise = new Promise((resolve, reject) => {
//     setTimeout(() => {
//       console.log('timer')
//       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) // 两个字几乎一样,状态一旦改变,就不会在变动了
//   })

//   Promise.resolve().then(() => {
//     return new Error('error!!!') // 被包裹成了return Promise.resolve(new Error('error!!!'))
//   }).then(res => {
//     console.log("then: ", res)
//   }).catch(err => {
//     console.log("catch: ", err)
//   })


/**
 * then链式调用
 */
// function runAsync1(){
//   var p = new Promise(function(resolve, reject){
//       //做一些异步操作
//       setTimeout(function(){
//           console.log('异步任务1执行完成');
//           resolve('随便什么数据1');
//       }, 2000);
//   });
//   return p;
// }
// function runAsync2(){
//   var p = new Promise(function(resolve, reject){
//       //做一些异步操作
//       setTimeout(function(){
//           console.log('异步任务2执行完成');
//           resolve('随便什么数据2');
//       }, 1000);
//   });
//   return p;
// }
// function runAsync3(){
//   var p = new Promise(function(resolve, reject){
//       //做一些异步操作
//       setTimeout(function(){
//           console.log('异步任务3执行完成');
//           resolve('随便什么数据3');
//       }, 1000);
//   });
//   return p;
// }

// runAsync1()
// .then(function(data){
//     console.log(data);
//     return runAsync2();
// })
// .then(function(data){
//     console.log(data);
//     return runAsync3();
// })
// .then(function(data){
//     console.log(data);
// });


/**
 * all: 所有异步任务完成执行then
 * race:执行快的直接跳出
 */
//  function runAsync (x) {
//     const p = new Promise(r => setTimeout(() => r(x, console.log(x)), 1000))
//     return p
// }
// Promise.all([runAsync(1), runAsync(2), runAsync(3)]) // 参数数组都是promise实例,如果不是强制包装
//   .then(res => console.log(res))

//   function runAsync (x) {
//     const p = new Promise(r => setTimeout(() => r(x, console.log(x)), 1000))
//     return p
//   }
//   function runReject (x) {
//     const p = new Promise((res, rej) => setTimeout(() => rej(`Error: ${x}`, console.log(x)), 1000 * x))
//     return p
//   }
//   Promise.all([runAsync(1), runReject(4), runAsync(3), runReject(2)])
//     .then(res => console.log(res))
//     .catch(err => console.log(err))

// let p1 = new Promise((resolve, reject) => {
//     setTimeout(() => {
//       resolve('success')
//     },1000)
//   })

//   let p2 = new Promise((resolve, reject) => {
//     setTimeout(() => {
//       reject('failed')
//     }, 3000)
//   })

//   Promise.race([p1, p2]).then((result) => {
//     console.log(result)
//   }).catch((error) => {
//     console.log(error)  // 打开的是 'success'
// })
  • 手写Promise api

Async、await

await可以看成是Promise的语法糖(实际上是Generate的语法糖),效果和Promise的回调地狱一样,只是代码看起来好看点。

测试代码
/**
 * async await
 */

//  async function fn () {
//     // return await 123
//     // 等同于
//     return 123
//   }
//   fn().then(res => console.log(res))
//   console.log(fn)

// async function async1() {
//     console.log("async1 start");
//     await async2();
//     console.log("async1 end");
//   }
// async function async2() {
//     console.log("async2");
//   }
// async1();
// console.log('start')

// async function async1() {
//     console.log("async1 start");
//     await async2(); // 紧跟着await后面的语句相当于放到了new Promise中,下一行及之后的语句相当于放在Promise.then中
//     console.log("async1 end");
//   }
// async function async2() {
//     setTimeout(() => {
//       console.log('timer')
//     }, 0)
//     console.log("async2");
//   }
// async1();
// console.log("start"

// async function async1() {
//   console.log("async1 start");
//   await async2();
//   console.log("async1 end");
//   setTimeout(() => {
//     console.log('timer1')
//   }, 0)
// }

// async function async2() {
//   setTimeout(() => {
//     console.log('timer2')
//   }, 0)
//   console.log("async2");
// }

// async1();

// setTimeout(() => {
//   console.log('timer3')
// }, 0)

// console.log("start")

综合

async function a1() {
  console.log('a1 start')
  await a2()
  console.log('a1 end')
}
async function a2() {
  console.log('a2')
}

console.log('script start')

setTimeout(() => {
  console.log('setTimeout')
}, 0)

Promise.resolve().then(() => {
  console.log('promise1')
})

a1()

let promise2 = new Promise(resolve => {
  resolve('promise2.then')
  console.log('promise2')
})

promise2.then(res => {
  console.log(res)
  Promise.resolve().then(() => {
    console.log('promise3')
  })
})
console.log('script end')

/** 第一次做错的结果
script start
a1 start
a2
promise1
a1 end
promise2
script end
promise2.then
promise3
setTimeout
 */

/** 正确结果
script start
a1 start
a2
promise2
script end
promise1
a1 end
promise2.then
promise3
setTimeout
 */

参考

评论区

Twikoo giscus