• 异步解决方案promise及源码实现


    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之类的一样。首先介绍一下它的用法吧!

      

    
    

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

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

      

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

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

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

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

    接下来增加链式调用功能

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

    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

    到此基本完成promise的基本功能,但还有一些方法没有实现,比如race ,all,也没有实现同时调用reject和resolve的问题,后续有时间再处理。有问题请指正

      

  • 相关阅读:
    你不是在拯救世界就是在拯救世界的路上
    你可以去当程序员了
    郭美美是个好姑娘
    据说有个老太太
    生命的尽头
    有关程序的50个至理名言
    程序员是这样的
    新买移动硬盘
    如果有天你看到我疯了,其实就是你疯了
    写字楼里写字间
  • 原文地址:https://www.cnblogs.com/shibaxiong/p/8570964.html
Copyright © 2020-2023  润新知