一 同步和异步、回调函数

  1. js的执行是单线程的,如此设计的原因是如果多个线程去操作dom就会变得复杂难控;因为是单线程,所以对于耗时较长的任务如果也同步执行的话就导致阻塞,所以有了异步;<br /> js引擎执行代码的时候,对于同步任务,首先会在执行栈里面创建一个匿名函数,或者叫执行环境;然后代码先压入栈,然后执行,执行完了出栈;对于声明的函数,不会立即入栈,只有在调用的时候才会入栈,调用完毕出栈;等所有代码执行完毕,清空栈;<br /> 在有异步任务的时候,会涉及到消息队列和内部apijs引擎先执行同步的代码,执行过程中遇到异步代码,会进入到内部api中,如setTimeout,会有浏览器线程单独倒计时这个timer(浏览器线程不是js线程),timer倒计时结束,会把这个timer的回调函数放入消息队列queue中,等同步代码执行完毕,消息队列中的函数会在执行栈中执行回调函数,入栈、出栈等;异步的代码又分宏任务和微任务,事件循环会在执行栈执行完同步任务后开始工作,遍历微任务队列,有的话就放到执行栈中去执行,直到清空了微任务队列,才去遍历宏任务队列,在遍历微任务队列的过程中出现了新的微任务,会加到当前微任务队列的末尾,而不是下个任务的微任务队列;然后再宏任务队列中,有就放到执行栈中去执行,执行完毕后清空栈;<br /> 回调函数时js所有异步的根基。回调函数由调用者定义,交给执行者去执行;

二 promise

promise是es2015新增的对象,参数是个函数,函数的参数有固定的resolve和reject,分别用来传递成功后的状态和失败后的状态;promise初始是pending状态,成功以后编程fullfilled,失败以后变成rejected;一旦状态改变,promise的状态就确定了,不可再更改;
promise例子

  1. function ajax(url) {
  2. return new Promise(function(resolve, reject) {
  3. var xhr = new XMLHttpRequest();
  4. xhr.open('GET', url);
  5. xhr.responseType = 'json';
  6. xhr.onload = function() {
  7. if(this.status == '200') {
  8. resolve(this.response)
  9. } else {
  10. reject(new Error(this.statusText))
  11. }
  12. }
  13. xhr.send();
  14. });
  15. }
  16. ajax('apis/user2.json').then(function(res){
  17. console.log(res)
  18. }, function(err){
  19. console.log(err)
  20. });

setTimeout 转换为promise

  1. // setTimeout(function(){
  2. // var a = 'hello ';
  3. // setTimeout(function(){
  4. // var b = ' lagou ';
  5. // setTimeout(function(){
  6. // var c = 'I love U';
  7. // console.log(a + b + c);
  8. // }, 10)
  9. // },10)
  10. // },10);
  11. let t = function(str) {
  12. return new Promise((resolve, reject) => {
  13. setTimeout(()=>{
  14. resolve(str)
  15. },10)
  16. });
  17. }
  18. let result = '';
  19. t('hello').then(function(data){
  20. result += data;
  21. return t(' there ')
  22. }).then(function(data){
  23. result += data;
  24. return t(' I love U')
  25. }).then(function(data) {
  26. result += data;
  27. console.log(result)
  28. })

promise 链式调用
promise的then返回一个全新的promise对象,所以可以链式调用;在then里面返回一个自定义新的promise也可以返回一个值;
后面的then方法就是在为上一个then返回的promise注册回调;前面then方法回调函数返回的值会作为后面then方法回调的参数;如果回调中返回的是promise,那后面then方法的回调会等待它的结束;

promise的异常处理
如果在promis执行的过程中出现了异常,就会触发reject回调;catch方法等同于then方法,只是回调的第一个参数为undefined;catch会捕获前面所有then里面的异常,但是reject只能捕获当前then里面的异常;
全局注册未捕获promise异常;浏览器中用unhandlerdreject注册到window对象,node中在process对象上注册unhandleredRejection事件;
推荐在每个promise中捕获异常,而不是到全局处理;

promise的静态方法
Promise.resove();Promise.reject()方法;通过promise.resolve包裹的promise对象回原样返回;

promise的并行方法
Promise.all([…promise]) 返回一个新的promise对象;等待所有promise结束才会执行then;
Promise.race([…promise]) 返回一个新的promise对象;等待数组中第一个promise结束就会执行then;常用来做接口超时处理;

微任务
promise、mutationObserver、nextTick会在当前任务执行完毕了立即执行;

三 generator


声明的generator函数第一次调用不会立即执行,将生成一个generator对象;后续调用对象的next方法时才会执行对于yield对应的表达式;执行一次,generator对象的指针会停留在当前语句;下次调用时会继续往下执行yield;只有遇到return或者函数结束了,才代表执行结束;此时next会返回done为true的状态;next方法的参数表示上一个yield表达式的返回值,所以在第一次使用next时传参是无效的,v8引擎会忽略第一次next方法的参数,从二次开始,next参数才有意义;
for…of循环可以自动遍历generator函数时生成的iterator对象,且此时不需要调用next方法;
generator的throw方法,可以在函数体内抛出错误,然后再generator函数内捕获;throw方法接受一个参数,该参数会被catch语句接受,建议抛出error对象实例;generator函数体内抛出的错误,可以在函数体外捕获;在generator中执行发生错误,且没有内部捕获就不会再执行下去,如果此后还调用next会返回undefined,done为true的对象,该generator执行完毕;
generator的return方法,可以返回给定的值并且终止遍历generator函数;如果return方法不提供参数,则返回值的value是undefined;如果generator函数内部有try…finaly代码,return方法会直接让其进入finaly代码块;
next、return、throw方法本质上都是为了让generator函数继续执行,只是使用不同的语句替换yield表达式;
如果generator函数嵌套generator函数,则必须在内部的generator函数中遍历,才能依次执行,否则调用内部函数只能返回一个function;此时,用yield表达式标记内部函数,就可以依次执行;
generator案例

  1. function ajax(url) {
  2. return new Promise(function(resolve, reject) {
  3. var xhr = new XMLHttpRequest();
  4. xhr.open('GET', url);
  5. xhr.responseType = 'json';
  6. xhr.onload = function() {
  7. if(this.status == '200') {
  8. resolve(this.response)
  9. } else {
  10. reject(new Error(this.statusText))
  11. }
  12. }
  13. xhr.send();
  14. });
  15. }
  16. // ajax('apis/user2.json').then(function(res){
  17. // console.log(res)
  18. // }, function(err){
  19. // console.log(err)
  20. // });
  21. function* main() {
  22. const user = yield ajax('/apis/user.json');
  23. console.log(user);
  24. }
  25. const g = main();
  26. const result = g.next();
  27. result.value.then(data => {
  28. g.next(data)
  29. })

四 async函数

async类似与generator函数;async函数对generator函数的改进体现在: 1 内置执行器;2 更好的语义;3 更广的适用性;

五 手写Promise

1 简单同步

  1. const PENDING = 'pending';
  2. const REJECTED = 'rejected';
  3. const FULFILLED = 'fulfilled';
  4. class MyPromise {
  5. constructor(exactor) {
  6. exactor(this.resolve, this.reject);
  7. }
  8. status = PENDING;
  9. value = undefined;
  10. reason = undefined;
  11. resolve = value => {
  12. if(this.status != PENDING) return;
  13. this.status = FULFILLED;
  14. this.value = value;
  15. }
  16. reject = reason => {
  17. if(this.status != PENDING) return;
  18. this.status = REJECTED;
  19. this.reason = reason;
  20. }
  21. then = (successCallback, failCallback) => {
  22. if(this.status == FULFILLED) {
  23. successCallback(this.value)
  24. } else if(this.status == REJECTED){
  25. failCallback(this.reason)
  26. }
  27. }
  28. }
  29. module.exports = MyPromise;

2 添加异步方法

  1. ...
  2. successCallback = undefined;
  3. failCallback = undefined;
  4. resolve = value => {
  5. ...
  6. this.successCallback && this.successCallback(this.value);
  7. }
  8. reject = reason => {
  9. ...
  10. this.failCallback && this.failCallback(this.reason);
  11. }
  12. then = (successCallback, failCallback) => {
  13. ...
  14. } else {
  15. this.successCallback = successCallback;
  16. this.failCallback = failCallback;
  17. }
  18. }
  19. }
  20. ...

3 添加多个then的处理

  1. ...
  2. successCallback = [];
  3. failCallback = [];
  4. resolve = value => {
  5. ...
  6. while(this.successCallback.length) this.successCallback.shift()(this.value);
  7. }
  8. reject = reason => {
  9. ...
  10. while(this.failCallback.length) this.failCallback.shift()(this.reason);
  11. }
  12. then = (successCallback, failCallback) => {
  13. ...
  14. } else {
  15. this.successCallback.push(successCallback);
  16. this.failCallback.push(failCallback);
  17. }
  18. }
  19. }
  20. module.exports = MyPromise;

4 链式调用

  1. ...
  2. then = (successCallback, failCallback) => {
  3. let promise2 = new MyPromise((resolve, reject)=>{
  4. if(this.status == FULFILLED) {
  5. let x = successCallback(this.value)
  6. resolve(x);
  7. } else if(this.status == REJECTED){
  8. let y = failCallback(this.reason);
  9. reject(y);
  10. } else {
  11. this.successCallback.push(successCallback);
  12. this.failCallback.push(failCallback);
  13. }
  14. });
  15. return promise2;
  16. }
  17. }
  18. ...

5 then 返回promise的情况

  1. ...
  2. then = (successCallback, failCallback) => {
  3. let promise2 = new Promise((resolve, reject)=>{
  4. if(this.status == FULFILLED) {
  5. let x = successCallback(this.value)
  6. resolvePromise(x,resolve, reject);
  7. } else if(this.status == REJECTED){
  8. failCallback(this.reason);
  9. } else {
  10. this.successCallback.push(successCallback);
  11. this.failCallback.push(failCallback);
  12. }
  13. });
  14. return promise2;
  15. }
  16. }
  17. function resolvePromise(x, resolve, reject) {
  18. if(x instanceof MyPromise) {
  19. x.then(resolve, reject)
  20. } else {
  21. resolve(x)
  22. }
  23. }
  24. ...

6 增加了在构造函数中发生异常、或者在then方法执行中发生异常的处理,另外增加了对then方法无参数回调的判断;

  1. ...
  2. constructor(exactor) {
  3. try{
  4. exactor(this.resolve, this.reject);
  5. }catch(error) {
  6. this.reject(error)
  7. }
  8. }
  9. ...
  10. then = (successCallback, failCallback) => {
  11. successCallback = successCallback? successCallback: value => value;
  12. failCallback = failCallback? failCallback: reason => {throw reason};
  13. let promise2 = new MyPromise((resolve, reject)=>{
  14. if(this.status == FULFILLED) {
  15. setTimeout(() => {
  16. try {
  17. let x = successCallback(this.value)
  18. resolvePromise(promise2, x,resolve, reject);
  19. } catch (e) {
  20. reject(e)
  21. }
  22. },0)
  23. } else if(this.status == REJECTED){
  24. setTimeout(() => {
  25. try {
  26. let x = failCallback(this.reason);
  27. resolvePromise(promise2, x,resolve, reject);
  28. } catch (e) {
  29. reject(e)
  30. }
  31. },0)
  32. } else {
  33. this.successCallback.push(() => {
  34. setTimeout(() => {
  35. try {
  36. let x = successCallback(this.value)
  37. resolvePromise(promise2, x,resolve, reject);
  38. } catch (e) {
  39. reject(e)
  40. }
  41. },0)
  42. });
  43. this.failCallback.push(()=> {
  44. setTimeout(() => {
  45. try {
  46. let x = failCallback(this.reason);
  47. resolvePromise(promise2, x,resolve, reject);
  48. } catch (e) {
  49. reject(e)
  50. }
  51. },0)
  52. });
  53. }
  54. });
  55. return promise2;
  56. }
  57. }
  58. ...

7 promise all方法

  1. ...
  2. static all = (array) => {
  3. let result = [];
  4. let index = 0;
  5. return new MyPromise((resolve, reject) => {
  6. function setData(key, value) {
  7. result[key] = value;
  8. index ++;
  9. if(index === array.length) {
  10. resolve(result)
  11. }
  12. }
  13. for (let i = 0; i < array.length; i++) {
  14. if (array[i] instanceof MyPromise) {
  15. // promise
  16. array[i].then(value => {
  17. setData(i, value)
  18. }, reason => {
  19. reject(reasonW)
  20. });
  21. } else {
  22. // 非promise
  23. setData(i, array[i]);
  24. }
  25. }
  26. });
  27. };
  28. }
  29. ...

8 promise resolve方法

  1. ...
  2. static resolve(value) {
  3. if(value instanceof MyPromise) return value;
  4. return new MyPromise(resolve => {resolve(value)})
  5. }
  6. ...

9 promise finally方法

  1. ...
  2. finally(finallyCallback){
  3. return this.then(value => {
  4. finallyCallback();
  5. return value;
  6. }, reason => {
  7. finallyCallback();
  8. throw reason;
  9. })
  10. }
  11. ...

10 finally方法返回promise

  1. ...
  2. finally(finallyCallback){
  3. return this.then(value => {
  4. return MyPromise.resolve(finallyCallback()).then(() => value)
  5. }, reason => {
  6. return MyPromise.resolve(finallyCallback()).then(()=> { throw reason });
  7. })
  8. }
  9. ...

11 catch 方法

  1. ...
  2. catch(failCallback) {
  3. return this.then(undefined, failCallback)
  4. }
  5. ...