JavaScript Promise执行流程深刻理解

目录
  • 手撕Promise
  • 看完收获
  • Promise分析
    • 作用
    • 特点
  • 总体实现
  • resolve和reject初步实现
  • then方法的实现
  • Promise.all的实现

手撕Promise

手写一个Promise已经是一个常见的手写功能了,虽然实际工作上可能并不会用到。但是在面试时还是会经常被提起的。

看完收获

  • 实现一个手写promise
  • 对promise执行流程有着更深刻的理解
  • 从底层理解proimse,应对各种面试题

Promise分析

作用

通过链式调用的方式,解决回调地狱的问题。

特点

是ES6中新增的引用类型,通过new关键词来创建实例。

存在3个状态:

  • pending
  • fulfilled
  • rejected

且状态变成fulfilled或者rejected后不可再次变更,具有不可逆性。

new Promise创建实例的时候必须要传入一个函数,且这个函数会有2个参数resolvereject

深入学习JavaScript中的promise

总体实现

首先我们可以按照Promise的特点来实现一个简单的总体结构。

  • 他是一个构造函数,每个创建的promise都有各自状态和值,且状态初始值为pending,值为undefined。
  • 创建实例的时候需要传入一个函数,而这个函数可以接受2个函数作为参数,这2个函数都有一个参数,且都可以更改实例的状态和值。
  • 根据Promise的结构,我们可以发现then()、catch()方法在它的原型上。
  function MyPromise(fn) {
      this.PromiseState = 'pending'
      this.PromiseResult = undefined;
      function resolve(data) {
      }
      function reject(error) {

      }
  }
  MyPromise.prototype.then = function(thenCallback) {
  }
  MyPromise.prototype.catch = function(catchCallback) {
  }

上述代码很简单,就定义了一个Promise的构造函数,有2个属性(PromiseState、PromiseResult)和2个方法(resolve、reject)。

原型上增加了then方法和catch方法,且这2个方法都接收一个函数。

而每次通过new来创建Promise的函数时,传入的函数会执行,因此我们直接调用fn函数,并传入resolve和reject这2个函数。

resolve和reject初步实现

resolve的调用会更改promise的状态和值,且状态是不可逆的。也就是说,只能从pending变成fulfilled或者rejected。而resolve函数的参数值会变成promise实例的值,reject同理。 所以我们把resolve和reject简单的写完整.

  function MyPromise(fn) {
    this.PromiseState = "pending";
    this.PromiseResult = undefined;
    // 保存实例对象的this的值
    const self = this;
    function resolve(data) { // 如果不使用self,这里内部的this会指向window
      // 如果当前的promise实例不是pending的状态就退出了,否则就更改当前的promise实例的状态和值
      if (self.PromiseState !== "pending") {
        return;
      }
      // 1.修改对象的状态([[promiseState]])
      // 2.设置对象结果值([[promiseResult]])
      self.PromiseState = "fulfilled";
      self.PromiseResult = data;
    }
    function reject(error) {
      if (self.PromiseState !== "pending") {
        return;
      }
      self.PromiseState = "rejected";
      self.PromiseResult = error;
    }
    fn(resolve, reject);
  }

上面代码中,resolve和reject就是用来更改当前实例的状态的,如果当前状态已经改变了,即不为pending,那么就不再进行状态变更和值变更了。

接下来就是验证一下:

  const p = new MyPromise((resolve, reject) => {
    resolve(1);
    reject(2);
  });
  console.log(p);

发现我们执行了resolve后再执行reject并不会再次更改状态。

但是还有一点,如果我们不执行resolve或者reject,而是直接执行throw呢?

先看看原生的Promise效果。

  const p1 = new Promise((resolve, reject) => {
    throw 111;
  });
  console.log(p1);

发现状态会变成rejected。

那我们是不是可以在执行fn(resolve,reject)的时候进行异常处理,将状态变成rejected,值变成该异常信息。

    // 如果throw异常,就需要捕获到异常然后更改状态
    try {
      // 同步调用执行器函数
      fn(resolve, reject);
    } catch (e) {
      // 修改promise对象的状态为失败
      reject(e);
    }

then方法的实现

then方法中我们知道它有2个参数,且这2个参数都是函数,第一个参数会在promise执行resolve时调用,第二个参数会在promise执行reject时调用。而.catch只不过是调用.then第二个参数的语法糖而已。

    const p = new Promise((resolve, reject) => {
    resolve(1);
  });
  const p1 = p.then(
    (res) => {
      console.log(res, "成功");
    },
    (err) => {
      console.log(err, "失败");
    }
  );
  console.log(p, 111);
  console.log(p1, 222);

但是我们查看原生的Promise后,可以发现,.then的执行会返回一个新的Promise实例。而决定调用.then的第几个参数,则是根据调用then的那个promise实例的状态决定。

修改代码如下:

  MyPromise.prototype.then = function (thenCallback, catchCallback) {
    return new Promise((resolve, reject) => {
      // 调用回调函数,要根据当前的promise实例来调用
      if (this.PromiseState === "fulfilled") {
        const result = thenCallback(this.PromiseResult);
        resolve(result);
      }
      if (this.PromiseState === "rejected") {
        const result = catchCallback(this.PromiseResult);
        resolve(result);
      }
    });
  };

我们的自定义函数上的原型的then返回了一个新的promise实例,而新的promise实例调用then的第几个参数则根据调用then的promise实例的状态决定(此处的this指向调用then的那个promise实例)。

我们需要拿到回调函数的执行结果,然后再放入新的promise实例的resolve中更改新实例的状态和值。

查看一下我们自己的效果:

  const p = new MyPromise((resolve, reject) => {
    reject(1);
  });
  const p1 = p.then(
    (res) => {
      console.log(res, "成功");
    },
    (err) => {
      console.log(err, "失败");
    }
  );
  console.log(p, 111);
  console.log(p1, 222);

这时候可能有人就会提出疑问,如果在上述的p中的回调里延时执行resolve或者reject呢?

  const p = new MyPromise((resolve, reject) => {
    setTimeout(() => {
      resolve(1);
    }, 1000);
  });
  const p1 = p.then(
    (res) => {
      console.log(res, "成功");
    },
    (err) => {
      console.log(err, "失败");
    }
  );
  console.log(p, 111);
  console.log(p1, 222);

我们可以发现p1的状态变成了pending。

这是因为当执行到setTimeout的时候,发现是一个异步函数,然后会将这个函数挂起,继续执行下面的.then(),然后当时的p的状态是pendding,因为不会执行任何代码。

那我们当然是要加一个pendding的判断啦!

可是该怎么实现判断的内部代码呢?

首先我们先来思考一下,promise是一个对象,他是按地址引用的。我们希望在定时器时间到的时候再去更改这个新的promise的状态和值。因此我们需要访问到上一个promise的状态和值,并且在resolve或者reject执行的时候访问到,而不是定时器挂起的时候。

  function MyPromise(fn) {
    this.PromiseState = "pending";
    this.PromiseResult = undefined;
    this.callback = {};
    // 保存实例对象的this的值
    const self = this;
    function resolve(data) {
      if (self.PromiseState !== "pending") {
        return;
      }
      // 1.修改对象的状态([[promiseState]])
      // 2.设置对象结果值([[promiseResult]])
      self.PromiseState = "fulfilled";
      self.PromiseResult = data;
      if (self.callback.onResolved) {
        self.callback.onResolved(data);
      }
    }
    function reject(error) {
      if (self.PromiseState !== "pending") {
        return;
      }
      self.PromiseState = "rejected";
      self.PromiseResult = error;
      if (self.callback.onReject) {
        self.callback.onReject(error);
      }
    }
    // 如果throw异常,就需要捕获到异常然后更改状态
    try {
      // 同步调用执行器函数
      fn(resolve, reject);
    } catch (e) {
      // 修改promise对象的状态为失败
      reject(e);
    }
  }
  MyPromise.prototype.then = function (thenCallback, catchCallback) {
    return new Promise((resolve, reject) => {
      // 调用回调函数,要根据当前的promise实例来调用
      if (this.PromiseState === "fulfilled") {
        const result = thenCallback(this.PromiseResult);
        resolve(result);
      }
      if (this.PromiseState === "rejected") {
        const result = catchCallback(this.PromiseResult);
        resolve(result);
      }
      // 判断pending状态
      if (this.PromiseState === "pending") {
        // 保存回调函数
        this.callback = {
          onResolved: function (data) {
            let result = thenCallback(data);
            resolve(result);
          },
          onRejected: function (error) {
            let result = catchCallback(error);
            resolve(result);
          },
        };
      }
    });
  };
  const p = new MyPromise((resolve, reject) => {
    setTimeout(() => {
      resolve(1);
    }, 1000);
  });
  const p1 = p.then(
    (res) => {
      console.log(res, "成功");
    },
    (err) => {
      console.log(err, "失败");
    }
  );

  console.log(p, 111);
  console.log(p1, 222);

因为new Promise的实例中遇到了异步的setTimeout会将内部的程序挂起,继续执行.then。

而这时promise实例的状态还是pending,因此我们需要对pending的状态进行处理,我们主要目的是,在setTimeout的回调函数执行的时候,能够执行.then的函数参数。

这时候就需要进行一个巧妙的设计,我们需要在MyPromise构造函数中增加一个callback的属性,他是一个对象。

同时我们需要在pending的时候在.then里面将then的两个参数传给callback对象,同时传入resolve的值或者是reject的值。

在pending的时候我们将函数传给了实例的callback,当被挂起的setTimeout回调函数执行的时候,这时候callback已经有值了,所以会根据resolve或者是reject去执行对应的函数,并且将promise的实例的值传给对应的函数。

那如我我对p多次调用.then或者.catch呢?

  const p = new MyPromise((resolve, reject) => {
    setTimeout(() => {
      resolve(1);
    }, 1000);
  });
  const p1 = p.then(
    (res) => {
      console.log(res, "成功");
    },
    (err) => {
      console.log(err, "失败");
    }
  );
  const p2 = p.then((res) => {
    console.log(res, "成功2");
  });
  console.log(p1, p2);

我们发现我们的值执行了一次,那我们看一下原生的,可以发现会执行2次。

  const p = new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(1);
    }, 1000);
  });
  const p1 = p.then(
    (res) => {
      console.log(res, "成功");
    },
    (err) => {
      console.log(err, "失败");
    }
  );
  const p2 = p.then((res) => {
    console.log(res, "成功2");
  });
  console.log(p1, p2);

原因很简单,因为我们的callback属性是一个对象,每次执行.then都会覆盖当前实例原先的callback。

怎么结局呢?很简单,我们只要将每次的pending时设置callback改成向数组加入对象就好。

调用时我们通过遍历去调用就好了。

  function MyPromise(fn) {
    this.PromiseState = "pending";
    this.PromiseResult = undefined;
    this.callbacks = [];
    // 保存实例对象的this的值
    const self = this;
    function resolve(data) {
      if (self.PromiseState !== "pending") {
        return;
      }
      // 1.修改对象的状态([[promiseState]])
      // 2.设置对象结果值([[promiseResult]])
      self.PromiseState = "fulfilled";
      self.PromiseResult = data;
      //调用成功的回调函数
      self.callbacks.forEach((item) => {
        item.onResolved(data);
      });
    }
    function reject(error) {
      if (self.PromiseState !== "pending") {
        return;
      }
      self.PromiseState = "rejected";
      self.PromiseResult = error;
      //执行失败的回调
      self.callbacks.forEach((item) => {
        item.onRejected(error);
      });
    }
    // 如果throw异常,就需要捕获到异常然后更改状态
    try {
      // 同步调用执行器函数
      fn(resolve, reject);
    } catch (e) {
      // 修改promise对象的状态为失败
      reject(e);
    }
  }
  MyPromise.prototype.then = function (thenCallback, catchCallback) {
    return new Promise((resolve, reject) => {
      // 调用回调函数,要根据当前的promise实例来调用
      if (this.PromiseState === "fulfilled") {
        const result = thenCallback(this.PromiseResult);
        resolve(result);
      }
      if (this.PromiseState === "rejected") {
        const result = catchCallback(this.PromiseResult);
        resolve(result);
      }
      // 判断pending状态
      if (this.PromiseState === "pending") {
        // 保存回调函数
        this.callbacks.push({
          onResolved: thenCallback,
          onRejected: catchCallback,
        });
      }
    });
  };
  const p = new MyPromise((resolve, reject) => {
    setTimeout(() => {
      resolve(1);
    }, 1000);
  });
  const p1 = p.then(
    (res) => {
      console.log(res, "成功");
    },
    (err) => {
      console.log(err, "失败");
    }
  );
  const p2 = p.then((res) => {
    console.log(res, "成功2");
  });
  console.log(p1, p2);

然后我们就发现我们可以正常地调用了。

那如果.then返回的值是一个promise呢?

这时候我们就需要考虑一下,如果.then返回时一个promise实例或者是一个throw错误呢?

  const p = new Promise((resolve, reject) => {
    resolve(1);
  });
  const p1 = p.then(
    (res) => {
      console.log(res, "成功");
      return new Promise((r, j) => {
        r(res);
      });
    },
    (err) => {
      console.log(err, "失败");
    }
  );
  console.log(p1, "p1");

我们先看一下原生的效果,发现他时拿到了返回的promise的值。

那是不是就是在调用then的回调函数的时候判断一下返回的是不是一个promise,如果是promise我们在进行特殊处理。

 // 将.then的判定方式改成如下
      if (this.PromiseState === "fulfilled") {
        try {
          const result = thenCallback(this.PromiseResult);
          if (result instanceof MyPromise) {
            result.then(
              (r) => {
                resolve(r);
              },
              (j) => {
                reject(j);
              }
            );
          } else {
            resolve(result);
          }
        } catch (e) {
          reject(e);
        }
      }
      if (this.PromiseState === "rejected") {
        try {
          const result = catchCallback(this.PromiseResult);
          if (result instanceof MyPromise) {
            result.then(
              (r) => {
                resolve(r);
              },
              (j) => {
                reject(j);
              }
            );
          } else {
            resolve(result);
          }
        } catch (e) {
          reject(e);
        }
      }

如果.then的回掉函数执行后返回的是一个promise实例,但是我们.then默认就返回了一个实例,我们就直接取这个实例的resolve值或者是reject值,将返回值给then默认返回的promise实例。

异步方式同理,但是要注意this的指向问题。

      // 判断pending状态
      if (this.PromiseState === "pending") {
        // 保存回调函数
        this.callbacks.push({
          onResolved: function () {
            try {
              // 这里的self指向的是调用.then的promise实例
              let result = thenCallback(self.PromiseResult);
              //判断
              if (result instanceof Promise) {
                result.then(
                  (v) => {
                    resolve(v);
                  },
                  (r) => {
                    reject(r);
                  }
                );
              } else {
                resolve(result);
              }
            } catch (e) {
              reject(e);
            }
          },
          onRejected: function () {
            try {
              // 这里的self指向的是调用.then的promise实例
              let result = catchCallback(self.PromiseResult);
              //判断
              if (result instanceof Promise) {
                result.then(
                  (v) => {
                    resolve(v);
                  },
                  (r) => {
                    reject(r);
                  }
                );
              } else {
                resolve(result);
              }
            } catch (e) {
              reject(e);
            }
          },
        });
      }
    });

我们发现,代码已经重复了4次,我们就可以进行一个封装。

  MyPromise.prototype.then = function (thenCallback, catchCallback) {
    const self = this;
    return new Promise((resolve, reject) => {
      function run(type) {
        try {
          //获取回调函数的执行结果
          let result = type(self.PromiseResult);
          //判断
          if (result instanceof Promise) {
            //如果是 Promise 类型的对象
            result.then(
              (v) => {
                resolve(v);
              },
              (j) => {
                reject(j);
              }
            );
          } else {
            //结果的对象状态为『成功』
            resolve(result);
          }
        } catch (e) {
          reject(e);
        }
      }
      // 调用回调函数,要根据当前的promise实例来调用
      if (this.PromiseState === "fulfilled") {
        run(thenCallback);
      }
      if (this.PromiseState === "rejected") {
        run(catchCallback);
      }
      // 判断pending状态
      if (this.PromiseState === "pending") {
        // 保存回调函数
        this.callbacks.push({
          onResolved: function () {
            run(thenCallback);
          },
          onRejected: function () {
            run(catchCallback);
          },
        });
      }
    });
  };

嗯,封装完后的一个完整的.then。我们先看一下完整的效果。

  const p1 = p.then(
    (res) => {
      console.log(res, "成功");
      return new Promise((r, j) => {
        r(res);
      });
    },
    (err) => {
      console.log(err, "失败");
    }
  );
  console.log(p1, "p1");

和原生的基本上是一模一样了。

接下来就是对catch的实现了

但是我们知道,catch其实就是.then执行第二个参数的一个语法糖。 因此,我们就可以将接收到的回调函数直接给.then的第二个参数。

MyPromise.prototype.catch = function(onRejected){
    return this.then(undefined, onRejected);
}

这时候我们就要注意了,我们给then的第一个参数赋值了一个undefined。但是我们并没有对undefined进行处理。而且我们原生的Promise是可以传入其他数据的,不一定是一个回调函数。

因此,我们需要在MyPromise的原型里的.then方法进行一个判断:

    if (typeof catchCallback !== "function") {
      catchCallback = (reason) => {
        throw reason;
      };
    }
    if (typeof thenCallback !== "function") {
      thenCallback = (value) => value;
    }

如果传入的不是一个函数,我们就将它变成一个函数,并且获取的是上一个.then返回的promise实例的值。

总体上我们大致完成了,但是Promise还存在构造函数的方法Promise.resolve(value)Promise.reject(error) 这个就很简单了

//添加 resolve 方法
MyPromise.resolve = function(value){
    //返回promise对象
    return new MyPromise((r, j) => {
        if(value instanceof MyPromise){
            value.then(v=>{
                r(v);
            }, r=>{
                j(r);
            })
        }else{
            //状态设置为成功
            resolve(value);
        }
    });
}

判断resolve传入的值是否是一个MyPromise实例,如果是,则根据这个Promise的状态来返回,如果不是则直接调用resolve()

reject同理:

//添加 reject 方法
MyPromise.reject = function(error){
    return new MyPromise((resolve, reject)=>{
        reject(error);
    });
}

Promise.all的实现

Promise.all的实现基于我们原先封装的MyPromise。

我们先来分析一下原先的Promise.all的方法,它接受一个promise数组,返回一个新的promise。如果数组中有一个状态是rejected,那将直接返回一个rejected的promise实例。如果都成功了,则返回成功的promise。

  MyPromise.all = function (promiseLists) {
    return new Promise((resolve, reject) => {
      let promiseResults = [];
      let count = 0;
      for (let i = 0; i < promiseLists.length; i++) {
        promiseLists.then(
          (v) => {
            count += 1;
            promiseResults[i] = v;
            if (count === promiseLists.length) {
              resolve(promiseResults);
            }
          },
          (err) => {
            reject(err);
          }
        );
      }
    });
  };

实现上我们定义了一个promiseLists的形参用来接收promise的数组。因为返回的肯定是一个promise,所以我们直接返回了一个promise的实例。

我们定义了一个count用来计数成功执行的个数,promiseResults则用来接收成功的结果(要按照顺序接收)。最后就是遍历promiseLists的数组了,如果是resolve则count+1,并且将值往promiseResults里面塞。如果count的值和接受的数组长度一样了,那就是全部的promise返回了fulfilled。如果有一个错误,则直接退出,并且将错误的promise的值传给all返回的promise。

到此这篇关于JavaScript Promise执行流程深刻理解的文章就介绍到这了,更多相关JavaScript Promise内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • javascript中Promise使用详解

    目录 一.首先,要知道为什么要用Promise语法? 二.接着,来了解一下回调地狱(Callback Hell) 三.最后,也是本章的重头戏,Promise的基本使用 (一) resolve函数 (二) rejected函数 (三)Promise的API 1. then 2. catch 3. finally 4. Promise.all 5. Promise.race 四.最后 前言: 做过前端开发的都知道,JavaScript是单线程语言,浏览器只分配给JS一个主线程,用来执行任务,但是每次

  • JS promise 的回调和 setTimeout 的回调到底谁先执行

    目录 任务 VS 微任务 执行过程 案例分析 结语 & 参考资料 首先提一个小问题:运行下面这段 JS 代码后控制台的输出是什么? console.log("script start"); setTimeout(function () { console.log("setTimeout1"); }, 0); new Promise((resolve, reject) => { setTimeout(function () { console.log(&

  • 彻底搞懂 javascript的Promise

    目录 一.为什么要引入Promise? Promise解决了什么问题? Promise有哪些具体的使用场景? 二.手写Prromise身上的方法 手写Promise.all 手写Promise.race 手写Promise.finally Promise.all和Promise.race的区别 Promise.all和Promise.race的应用场景 promise.all()的应用场景 Promise.race()的应用场景 三.Promise是如何解决串行和并行的? 什么是并行?什么是串行

  • JS Promise axios 请求结果后面的.then() 是什么意思

    目录 Promise 对象 Promise 对象的状态 回调函数 Promise.then() 绑定回调函数 使用 Promise:链式调用 链式调用的实现 错误处理 常见错误 创建 Promise 对象 Promise 其他静态方法 创建已决议的 Promise 对象 多个 Promise 对象 结语&参考文献 Promise 是JS中一种处理异步操作的机制,在现在的前端代码中使用频率很高.Promise 这个词可能有点眼生,但你肯定见过 axios.get(...).then(res =>

  • JavaScript中的Promise详解

    目录 Promise的基本用法: 1.创建Promise对象 2.Promise 方法 总结 Promise是异步编程的一种解决方案,是一个对象,可以获取异步操作的消息,大大改善了异步编程的困难,避免了回调地狱,比传统的解决方案回调函数和事件更合理和更强大. 从语法上讲,Promise是一个对象,它可以获取异步操作的消息.提供了一个统一的API,各种异步操作都可以用同样的方法进行处理 1.Promise的实例有三个状态: (1)Pending(进行中) (2)Resolved(已完成) (3)R

  • JavaScript中Promise的执行顺序详解

    目录 前言 代码分析 then 方法何时调用? 总结 前言 最近看到一个 Promise 相关的很有意思的代码: new Promise((resolve) => { console.log(1) resolve() }).then(() => { new Promise((resolve) => { console.log(2) resolve() }).then(() => { console.log(4) }) }).then(() => { console.log(3

  • JavaScript Promise执行流程深刻理解

    目录 手撕Promise 看完收获 Promise分析 作用 特点 总体实现 resolve和reject初步实现 then方法的实现 Promise.all的实现 手撕Promise 手写一个Promise已经是一个常见的手写功能了,虽然实际工作上可能并不会用到.但是在面试时还是会经常被提起的. 看完收获 实现一个手写promise 对promise执行流程有着更深刻的理解 从底层理解proimse,应对各种面试题 Promise分析 作用 通过链式调用的方式,解决回调地狱的问题. 特点 是E

  • JavaScript中“+”的陷阱深刻理解

    一.两个中括号相加 [] + [] 中括号没有语句块的作用,因此这里的两个中括号就是一个数组.两个数组(对象类型)相加先要将其转换成值类型(基本类型). 1,转成值类型调用valueOf,[]的valueOf()还是自己 复制代码 代码如下: var arr = []; arr.valueOf() === arr; // true 2,转成字符串,[]的toString是空字符串 复制代码 代码如下: [].toString(); // "" String([]) // "&

  • 深入理解javascript的执行顺序

    如果你不能理解javaScript语言的运行机制,或者简单地说,你不能掌握javascript的执行顺序,那你就犹如伯乐驾驭不了千里马,让千里马脱缰而出,四处乱窜. 那么JavaScript是怎么来进行解析的吗?它的执行顺序又是如何的呢?在了解这些之前,我们先来认识几个重要的术语: 1.代码块JavaScript中的代码块是指由<script>标签分割的代码段.例如: 复制代码 代码如下: <script type="text/javascript">     

  • 详解JavaScript引擎V8执行流程

    目录 一.V8来源 二.V8的服务对象 三.V8的早期架构 四.V8早期架构的缺陷 五.V8的现有架构 六.V8的词法分析和语法分析 七.V8 AST抽象语法树 八.字节码 九.Turbofan 一.V8来源 V8的名字来源于汽车的"V型8缸发动机"(V8发动机).V8发动机主要是美国发展起来,因为马力十足而广为人知.V8引擎的命名是Google向用户展示它是一款强力并且高速的JavaScript引擎. V8未诞生之前,早期主流的JavaScript引擎是JavaScriptCore引

  • Javascript变量函数声明提升深刻理解

    目录 前言: 变量提升 函数提升 为什么要提升? 最佳实践 总结 前言: Javascript变量函数声明提升(Hoisting)是在 Javascript 中执行上下文工作方式的一种认识(也可以说是一种预编译),从字面意义上看,“变量提升”意味着变量和函数的声明会在物理层面移动到代码的最前面,在代码里的位置是不会动的,而是在编译阶段被放入内存中会和代码顺序不一样.变量函数声明提升虽然对于实际编码影响不大,特别是现在ES6的普及,但作为前端算是一个基础知识,必须掌握的,是很多大厂的前端面试必问的

  • Javascript Promise用法详解

    1.约定 本文的 demo 代码有些是伪代码,不可以直接执行. 没有特殊说明,本文所有 demo 都是基于 ES6 规范. Object.method 代表是静态方法, Object#method 代表的是实例方法.如 Promise#then 代表的是 Promise 的实例方法, Promise.resolve 代表的是 Promise 的静态方法. 2.什么是 Promise? 首先我们来了解 Promise 到底是怎么一回事 Promise 是抽象的异步处理对象,以及对其进行各种操作的组

  • 跟我学习javascript的执行上下文

    在这篇文章里,我将深入研究JavaScript中最基本的部分--执行上下文(execution context).读完本文后,你应该清楚了解释器做了什么,为什么函数和变量能在声明前使用以及他们的值是如何决定的. 1.EC-执行环境或者执行上下文 每当控制器到达ECMAScript可执行代码的时候,控制器就进入了一个执行上下文(好高大上的概念啊). javascript中,EC分为三种: 全局级别的代码 –– 这个是默认的代码运行环境,一旦代码被载入,引擎最先进入的就是这个环境. 函数级别的代码

  • js对象实例详解(JavaScript对象深度剖析,深度理解js对象)

    这算是酝酿很久的一篇文章了. JavaScript作为一个基于对象(没有类的概念)的语言,从入门到精通到放弃一直会被对象这个问题围绕. 平时发的文章基本都是开发中遇到的问题和对最佳解决方案的探讨,终于忍不住要写一篇基础概念类的文章了. 本文探讨以下问题,在座的朋友各取所需,欢迎批评指正: 1.创建对象 2.__proto__与prototype 3.继承与原型链 4.对象的深度克隆 5.一些Object的方法与需要注意的点 6.ES6新增特性 下面反复提到实例对象和原型对象,通过构造函数 new

  • 详解JavaScript Promise和Async/Await

    概述 一般在开发中,查询网络API操作时往往是比较耗时的,这意味着可能需要一段时间的等待才能获得响应.因此,为了避免程序在请求时无响应的情况,异步编程就成为了开发人员的一项基本技能. 在JavaScript中处理异步操作时,通常我们经常会听到 "Promise "这个概念.但要理解它的工作原理及使用方法可能会比较抽象和难以理解. 四个示例 那么,在本文中我们将会通过实践的方式让你能更快速的理解它们的概念和用法,所以与许多传统干巴巴的教程都不同,我们将通过以下四个示例开始: 示例1:用生

  • 关于JavaScript回调函数的深入理解

    前言 JavaScript回调函数是成为一名成功的 JavaScript 开发人员必须要了解的一个重要概念.但是我相信,在阅读本文之后,你将能够克服以前使用回调方法遇到的所有障碍. 在开始之前,首先要确保我们对函数的理解是扎实的. 快速回顾:JavaScript 函数 什么是函数? 函数是在其中有一组代码的逻辑构件,用来执行特定任务.实际上为了易于调试和维护,函数允许以更有组织的方式去编写代码.函数还允许代码重用. 你只需定义一次函数,然后在需要时去调用它,而不必一次又一次地编写相同的代码. 声

随机推荐