资讯专栏INFORMATION COLUMN

十几行代码教你实现一个最简版的promise

SQC / 1992人阅读

摘要:最近研究了一下的实现,这篇文章使用了十几行代码实现了一个简单的以便帮助读者对有更深的了解。另外一个有三种状态。所以我们有以下的代码然后我们实现函数每次函数的执行会返回一个新的。因为这行代码是异步执行的,而当中的时,这行代码不应该执行。

最近研究了一下promise的实现,这篇文章使用了十几行代码实现了一个简单的promise;以便帮助读者对promise"有更深的了解。本篇文章实现的promise,遵循规范是 Promises/A+。

阅读本篇文章时,已经假定你会promise的基本使用和一些简单的es6语法;如果你还没掌握promise的基本使用,请学习完毕后再来。推荐可以看《promise迷你书》、《你不知道的js》及阮一峰老师的《ECMAScript 6 入门》。

promise的核心实现

首先,我们看一下一个promise的基本用法:

var p = new MyPromise((resolve) => {
    setTimeout(() => {
        resolve(20)
    }, 300)
})
p.then( (msg) => console.log(msg) );

MyPromise是一个构造函数,这个构造函数会被传递一个函数;函数中有两个参数,是两个函数resolve,reject。另外一个promise有三种状态PENDING、RESOLVED、REJECTED。所以我们有以下的代码:

const PENDING = 0;
const RESOLVED = 1;
const REJECTED = 2;  
function MyPromise(func){
    let state = PENDING;
    let value = null;
    function resolve(newValue){
        value = newValue;
        state = RESOLVED;
    }
    function reject(err){
        value = err;
        state = REJECTED;
    }
    func(resolve, reject);
}

然后我们实现then函数,每次then函数的执行会返回一个新的promise。

this.then = function(onFullFill, onReject){
    return new MyPromise((resolve, reject) => {
        
    })
}

传递给then函数onFullFill函数返回值,会传递给第二个then中onFullFill中。即要能这样使用p.then( (msg) => msg ).then( data => console.log(data) );
这行代码实际是什么呢?让我们变换一下上面的代码:

p
  .then( function fn1(msg){
      return msg;
  })
  .then( function fn2(data){
      console.log(data);
  })
//以上代码的实质
fn2(fn1(msg))

我们要在then函数里面如何执行resolve函数呢?首先resolve函数是必须执行的,因为它要改变p.then()生成的promise的状态;其次,resolve这个函数还要能接受到onFullFill执行的值;以便传递给下一个回调函数。你可能想到了这种方案:

const PENDING = 0;
const RESOLVED = 1;
const REJECTED = 2;  
function MyPromise(func){
    let state = PENDING;
    let value = null;
    function resolve(newValue){
        value = newValue;
        state = RESOLVED;
    }
    function reject(err){
        value = err;
        state = REJECTED;
    }
    this.then = function(onFullFill, onReject){
        return new MyPromise((resolve, reject) => {
            resolve(onFullFill(value));
        })
    }
    func(resolve, reject);
}

var p = new MyPromise((resolve) => {
    setTimeout(() => {
        resolve(20)
    }, 300)
})

p.then( (msg) => msg ).then( data => console.log(data) );

但是当你把以上代码拼凑在一起,执行;打印出来的是null。why?

因为setTimeout(fn, 300)这行代码是异步执行的,而当promise中的state!==RESOLVED时,这行代码resolve(onFullFill(value));不应该执行。所以我们有了以下的优化:

function MyPromise(func){
    let state = PENDING;
    let value = null;
    let handlers = [];
    function resolve(newValue){
        value = newValue;
        state = RESOLVED;
        handlers.forEach( handler => handle(handler));
    }
    function reject(err){
        value = err;
        state = REJECTED;
    }
    function handle(handler){
        if(state === PENDING){
            handlers.push(handler);
            return;
        }
        handler.resolve(handler.onFullFill(value));
    }
    this.then = function(onFullFill, onReject){
        return new MyPromise((resolve, reject) => {
            handle({
                resolve: resolve,
                onFullFill: onFullFill
            })
        })
    }
    func(resolve, reject);
}

这样在then函数里和resolve函数里我们都会执行handle函数,但只有在resolve函数执行后才会执行handler.resolve(handler.onFullFill(value))
现在还有一个问题,如果Promise中封装的不是异步操作,而是同步操作;那么resolve函数就会比then函数更先执行。

var p = new MyPromise((resolve, reject) => {
    resolve("同步操作")
})
p.then(console.log)

所以我们执行resolve中的回调的时候,应该异步执行:

function resolve(newValue){
    value = newValue;
    state = RESOLVED;
    setTimeout( () => {
        handlers.forEach( handler => handle(handler));
    }, 0)
}

同时,由于then函数中可以接收一个promise;我们需要对这种情况进行处理:

function resolve = (newValue) => {
  if(newValue && (typeof newValue === "object" || typeonewValue === "function") {
    let then = newValue.then
    if(typeof then === "function"){
      return then.call(newValue, resolve)
    }
  
  state = FULFILLED;
  value = newValue;
  setTimeout(() => {
    handlers.forEach(handler => {
      handle(handler)
    })
  }, 0)
}

至此,我们已经完成了一个基本promise的实现。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/83498.html

相关文章

  • 十几代码教你实现一个最简版的promise

    摘要:最近研究了一下的实现,这篇文章使用了十几行代码实现了一个简单的以便帮助读者对有更深的了解。另外一个有三种状态。所以我们有以下的代码然后我们实现函数每次函数的执行会返回一个新的。因为这行代码是异步执行的,而当中的时,这行代码不应该执行。 最近研究了一下promise的实现,这篇文章使用了十几行代码实现了一个简单的promise;以便帮助读者对promise有更深的了解。本篇文章实现的pr...

    tracymac7 评论0 收藏0
  • 引言 下面是一个使用脚手架来初始化项目的典型例子。 showImg(https://segmentfault.com/img/remote/1460000019219651?w=1312&h=533); 随着前端工程化的理念不断深入,越来越多的人选择使用脚手架来从零到一搭建自己的项目。其中大家最熟悉的就是create-react-app和vue-cli,它们可以帮助我们初始化配置、生成项目结构、自...

    AnthonyHan 评论0 收藏0
  • 如何快速开发一个自己的项目脚手架?

    摘要:开发一个自己的脚手架了解了一些脚手架的工作方式与的基本概念,咱们就可以来创建一个属于自己的脚手架。引言 下面是一个使用脚手架来初始化项目的典型例子。   showImg(https://user-gold-cdn.xitu.io/2019/5/16/16ac081750971790);     随着前端工程化的理念不断深入,越来越多的人选择使用脚手架来从零到一...

    alighters 评论0 收藏0
  • JS每日一题:函数式编程中代码组合(compose)如何理解?

    摘要:期函数式编程中代码组合如何理解定义顾名思义,在函数式编程中,就是将几个有特点的函数拼凑在一起,让它们结合,产生一个崭新的函数代码理解一个将小写转大写的函数一个在字符后加的函数将两个函数组合起来这里假设我们实现了每日一题每日一题显示结果里上面 20190315期 函数式编程中代码组合(compose)如何理解? 定义: 顾名思义,在函数式编程中,Compose就是将几个有特点的函数拼凑在...

    Kaede 评论0 收藏0
  • 【教学向】再加150代码教你实现一个低配版的web component库(1) —设计篇

    摘要:为的内置一个方法,用法和原生的事件机制一毛一样。 前言 上两篇Mvvm教程的热度超出我的预期,很多码友留言表扬同时希望我继续出下一篇教程,当时我也半开玩笑说只要点赞超10就兑现承诺,没想到还真破了10,所以就有了今天的文章。 准备工作 熟读 【教学向】150行代码教你实现一个低配版的MVVM库(1)- 原理篇【教学向】150行代码教你实现一个低配版的MVVM库(2)- 代码篇 本篇是在...

    Clect 评论0 收藏0

发表评论

0条评论

SQC

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<