js语言的特性,造就了特别的异步处理方式,我记得以前用的最多的就是回调函数,那个时候写jquery的ajax时候,特别喜欢写这种代码:

$.ajax({

  method:'get',

  url:"http://text/api",

  success:function(){

      $.ajax({

        method:'get',

        url:"http://text/api",

        success:function(){

      }

    });

  }

});

后一个ajax的发送需要依赖前面的ajax的返回,也许有的朋友说还好啊,其实一两个确实还好,但是多了就比较晕。不直观。后面调试起来有点麻烦。后来很多浏览器就自己实现了一种promise原生对象,这个对象提供一系列方法,来解决这种回调带来的不直观,不易维护的问题。

  首先,这个promise很多浏览器已经实现了,开发者只需要调用就可以,就像window,document之类的一样。首先介绍一下它的用法吧!

  

  1.  

  我们需要通过new调用Promise对象,这个对象需要传入一个函数,函数有两个参数,分别是resolve,reject,分别代表成功和失败两种状态,同时还有一个then的方法,它也有两函数作为参数,第一个表示任务处理成功的后续操作,第二个表示任务处理失败的后续操作,当我们调用实例上的then 的方法后,promise会根据我们在new Promise过程中调用的是resolve还是reject来判断应该执行哪一个函数。

  这样我们可以简单粗暴的改写一个上面那个ajax的代码

  

  这样一来代码变的更加明了,而且then方法可以一直链式调用下去,不管有多少异步任务都可以通过then方法写下去。

  接下来,我们看看怎么模拟这种操作,写一个自己的promise。

  首先,我们需要设定三种状态,成功,失败 和 等待,也就是一个任务完成的情况,做完了就是成功,没做好就是失败,还没开始做就是等待。

这就完成了一个promise最基本的功能,此时,如果在excutor函数中,出现一个异步任务,需要等待一秒才能执行resolve或者reject,此时状态会处于pending,我们需要做一个数组,把这些等着状态的任务装起来,在reject或者resolve执行时候,遍历数组,一个一个依次执行。

接下来增加链式调用功能

到此我们还要解决用户在then方法中随意返回数据的问题,用户可能返回一个普通值,也可能返回一个新的promise,因此还需要作进一步处理

  1. function Promise(executor) { // executor是一个执行函数
    let self = this;
    self.status = 'pending';
    self.value = undefined; // 默认成功的值
    self.reason = undefined; // 默认失败的原因
    self.onResolvedCallbacks = []; // 存放then成功的回调
    self.onRejectedCallbacks = []; // 存放then失败的回调
    function resolve(value) { // 成功状态
    if (self.status === 'pending') {
    self.status = 'resolved';
    self.value = value;
    self.onResolvedCallbacks.forEach(function (fn) {
    fn();
    });
    }
    }
    function reject(reason) { // 失败状态
    if (self.status === 'pending') {
    self.status = 'rejected';
    self.reason = reason;
    self.onRejectedCallbacks.forEach(function (fn) {
    fn();
    })
    }
    }
    try {
    executor(resolve, reject)
    } catch (e) { // 捕获的时候发生异常,就直接失败了
    reject(e);
    }
    }
    function resolvePromise(p2,x,resolve,reject){
    // 有可能这里返回的x是别人的promise
    // 尽可能允许其他乱写
    if(p2===x){ //这里应该报一个类型错误,有问题
    return reject(new TypeError('循环引用了'))
    }
    // 看x是不是一个promise,promise应该是一个对象
    if(x!==null||(typeof x === 'object'||typeof x === 'function')){
    // 可能是promise {},看这个对象中是否有then方法,如果有then我就认为他是promise了
    try{ // {then:1}
    let then = x.then;
    if(typeof then === 'function'){
    // 成功
    then.call(x,function(y){
    // y可能还是一个promise,在去解析直到返回的是一个普通值
    resolvePromise(promise2,y,resolve,reject)
    },function(err){ //失败
    reject(err);
    })
    }else{
    resolve(x)
    }
    }catch(e){
    reject(e);
    }
    }else{ // 说明是一个普通值1
    resolve(x); // 表示成功了
    }
    }
    Promise.prototype.then = function (onFulfilled, onRjected) {
    let self = this;
    let promise2; //返回的promise
    if (self.status === 'resolved') {
    promise2 = new Promise(function (resolve, reject) {
    // 当成功或者失败执行时有异常那么返回的promise应该处于失败状态
    // x可能是一个promise 也有可能是一个普通的值
    let x = onFulfilled(self.value);
    // x可能是别人promise,写一个方法统一处理
    resolvePromise(promise2,x,resolve,reject);
    })
    }
    if (self.status === 'rejected') {
    promise2 = new Promise(function (resolve, reject) {
    let x = onRjected(self.reason);
    resolvePromise(promise2,x,resolve,reject);
    })
    }
    // 当调用then时可能没成功 也没失败
    if (self.status === 'pending') {
    promise2 = new Promise(function (resolve, reject) {
    // 此时没有resolve 也没有reject
    self.onResolvedCallbacks.push(function () {
    let x = onFulfilled(self.value);
    resolvePromise(promise2,x,resolve,reject);
    });
    self.onRejectedCallbacks.push(function () {
    let x = onRjected(self.reason);
    resolvePromise(promise2,x,resolve,reject);
    });
    })
    }
    return promise2;
    }
    // mjs
    module.exports = Promise
  2.  
  3. 到此基本完成promise的基本功能,但还有一些方法没有实现,比如race ,all,也没有实现同时调用rejectresolve的问题,后续有时间再处理。有问题请指正

  

异步解决方案promise及源码实现的更多相关文章

  1. JS魔法堂: Native Promise Only源码剖析

    一, 前言 深入学习Promise的朋友应该都看过<深入理解Promise五部曲>这一系列的文章, 以解除回调地狱之外的观点来剖析Promise更多的内涵,确实十分精彩. Part 1: ...

  2. Promise的源码实现(完美符合Promise/A+规范)

    Promise是前端面试中的高频问题,我作为面试官的时候,问Promise的概率超过90%,据我所知,大多数公司,都会问一些关于Promise的问题.如果你能根据PromiseA+的规范,写出符合规范 ...

  3. 异步编程之co——源码分析

    异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...

  4. promise/bluebird源码

    本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/bluebirdsource 本博客同步在http://www.cnb ...

  5. ES6学习笔记(十二)异步解决方案Promise

    1.Promise 的含义 Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大.它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了P ...

  6. 学习 opencv---(6)玩转opencv源代码:生成opencv 工程解决方案与opencv 源码编译

    在这篇中,我们探讨如何通过已安装的opencv选择不同的编译器类型,生成高度还原的OpenCV开发时的解决方案工程文件,欣赏OpenCV新版本中总计 六十六多万行的精妙源代码.我们可以对其源代码进行再 ...

  7. mfc 调用Windows的API函数实现同步异步串口通信(源码)

    在工业控制中,工控机(一般都基于Windows平台)经常需要与智能仪表通过串口进行通信.串口通信方便易行,应用广泛. 一般情况下,工控机和各智能仪表通过RS485总线进行通信.RS485的通信方式是半 ...

  8. C# Retry重试操作解决方案(附源码)

    一.前言 (1)对于Thread的Abort方法,如果线程当前正在执行的是一段非托管代码,那么CLR就不会抛出ThreadAbortException,只有当代码继续回到CLR中时,才会引发Threa ...

  9. 异步解决方案----Promise与Await

    前言 异步编程模式在前端开发过程中,显得越来越重要.从最开始的XHR到封装后的Ajax都在试图解决异步编程过程中的问题.随着ES6新标准的到来,处理异步数据流又有了新的方案.我们都知道,在传统的aja ...

随机推荐

  1. Lua内存分析工具

    最近给公司写了一个lua内存分析工具,可以非常方便的分析出Lua内存泄露问题,有图形化界面操作,方便手机端上传快照等功能 内存分析我是在c语言端写的,也有人写过lua端的分析工具,也蛮好用的,不过lu ...

  2. 洛谷P1854 花店橱窗布置 分析+题解代码

    洛谷P1854 花店橱窗布置 分析+题解代码 蒟蒻的第一道提高+/省选-,纪念一下. 题目描述: 某花店现有F束花,每一束花的品种都不一样,同时至少有同样数量的花瓶,被按顺序摆成一行,花瓶的位置是固定 ...

  3. angular2^ typescript 将 文件和Json数据 合并发送到服务器(1.客户端处理)

    首先介绍下框架基本流程   (web > webservice  [前端架构] ) > (nodejs [ 数据中转站 ]) >(api [后台接口]) --web (html  a ...

  4. 浅谈Java SE、Java EE、Java ME三者的区别

    本文把JAVA SE.JAVA EE.JAVA ME拿来做下区别,同时也分享一下作者的一些成果.目前的Java平台根据软件开发人员.服务提供商和设备生产商可以针对特定的市场可以分为三个版本JAVA S ...

  5. mdb导入SqlServer

    弄了一份医案数据库,打开一看...命名全中文,好吧,导入SQLServer走起 SQL: SELECT * INTO newtable FROM OPENDATASOURCE ('Microsoft. ...

  6. Halcon一日一练:图像拼接技术2:步骤与例程

    上一篇主要介绍了图像拼接的一些原理和方法,这一篇将主要介绍步骤和例程: 接上一篇: 基于特征的接拼方法,分为四个步骤 1.特征检测:从图像中检测出显著且独特的图像特征,诸如:闭合区域,直线段,边缘,轮 ...

  7. toString 方法在数组中的使用

    对于一个一维数组,他在转换成字符串的时候应该调用Arrays.toString(); 对于一个多维数组,他在转换成字符串的时候应该调用Arrays.deepToString(); 实例: packag ...

  8. Nexus3将本地jar包添加到仓库

    新建一个文件夹,将要上传的jar包放进去,然后创建一个pom文件,例如xx.jar,pom.xml 首先创建一个目录 方便执行上传的时候url参数 也可以不创建, 上传XML curl -v -u a ...

  9. onclick与this

    这个其实也是一个很基础的问题,不过又碰巧遇到了,所以记录一下. 假设我们有这么一个需求,按下按钮,弹出提示框,显示按钮的value值. 可能有一些人提起笔就写: <button onclick= ...

  10. Python 实现单例模式的一些思考

    一.问题:Python中如何实现单例模式 单例模式指一个类只能实例化一个对象. 二.解决方案: 所有资料参考于: http://python.jobbole.com/87294/ https://ww ...