Promise

1、简易版Promise

const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'

function MyPromise(fn) {
    const that = this
    that.state = PENDING
    that.value = null
    that.resolvedCallbacks = []
    that.rejectedCallbacks = []
    // 待完善resolve和reject函数
    // 待完善执行 fn 函数
}
复制代码
  • 首先咱们建立了三个常量用于表示状态,对于常用的一些值都应该经过常量来管理,便于开发及后期维护。
  • 在函数体内部首先建立了常量that,由于代码可能会异步执行,用于获取正确的this对象
  • 一开始Promise的状态应该是pending
  • value 变量用于保存 resolve 或者 reject 中传入的值
  • resolvedCallbacks 和 rejectedCallbacks 用于保存 then 中的回调,由于当执行完 Promise 时状态可能仍是等待中,这时候应该把then中的回调保存起来用于状态改变时使用

接下来咱们来完善 resolve 和 reject 函数,添加在 MyPromise函数体内部数组

function resolve(value) {
    if (that.state === PENDING) {
        that.state = RESOLVED
        that.value = value
        that.resolvedCallbacks.map(cb => cb(that.value))
    }
}

function reject(value) {
    if (that.state === PENDING) {
        that.state = REJECTED
        that.value = value
        that.rejectedCallbacks.map(cb => cb(that.value))
    }
}
复制代码
  • 首先两个函数都得判断当前状态是否都为等待中,由于规范只有等待态才能够改变状态
  • 将当前状态更改成对应状态,而且将闯入的值赋值给value
  • 遍历回调数组并执行

完成以上两个函数之后,咱们就该实现如何执行Promise中传入的函数了promise

try {
    fn(resolve, reject)
} catch (e) {
    reject(e)
}
复制代码
  • 实现很简单,执行传入的参数而且将以前两个函数当作参数传进去
  • 要注意的是,可能执行函数过程当中会遇到错误,须要捕获错误而且执行reject函数

最后咱们来实现较为复杂的then函数bash

MyPromise.prototype.then = function(onFulfilled, onRejected) {
    const that = this
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v
    onRejected = typeof onRejected == 'function' ? onRejected : r => {
        throw r
    }
    if (that.state === PENDING) {
        that.resolvedCallbacks.push(onFulfilled)
        that.rejectedCallbacks.push(onRejected)
    }
    if (that.state === RESOLVED) {
        onFulfilled(that.value)
    }
    if (that.state === REJECTED) {
        onRejected(that.value)
    }
}
复制代码
  • 首先判断两个参数是否为函数类型,由于这两个参数是可选参数
  • 当参数不是函数类型时,须要建立一个函数赋值为对应的参数,同时也实现了透传,以下代码
// 该代码目前在简单版中会报错,只是做为一个透传的例子
Promise.resolve(4).then().then((value) => console.log(value))
复制代码
  • 接下来就是一系列判断状态的逻辑,当状态不是等待时,就去执行相对应的函数。若是状态是等待态的话,就往回调函数中 push 函数,好比以下代码就会进入等待态的逻辑
new MyPromise((resolve, reject) => {
    setTimeout(() => {
        resolve(1)
    },0)
}).then(value => {
    console.log(value)
})
复制代码

以上就是简单版Promise的实现。异步

const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'

function MyPromise(fn) {
    const that = this
    that.state = PENDING
    that.value = null
    that.resolvedCallbacks = []
    that.resolvedCallbacks = []
    
    function resolve(value) {
        if (that.state === PENDING) {
            that.state = RESOLVED
            that.value = value
            that.resolvedCallbacks.map(cb => cb(that.value))
        }
    }
    
    function reject(value) {
        if (that.state === PENDING) {
            that.state = REJECTED
            that.value = value
            that.rejectedCallbacks.map(cb => cb(that.value))
        }
    }
    
    try {
        fn(resolve, reject)
    } catch (e) {
        reject(e)
    }
}

MyPromise.prototype.then = function(onFulfilled, onRejected) {
    const that = this
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v
    onRejected = typeof onRejected === 'function' ? onRejected : r => {
        throw r
    }
    
    if (that.state === PENDING) {
        that.resolvedCallbacks.push(onFulfilled)
        that.rejectedCallbacks.push(onRejected)
    }
    
    if (that.state === RESOLVED) {
        onFulfilled(that.value)
    }
    if (that.state === REJECTED) {
        onRejected(that.value)
    }
}
// 此匿名函数接受两个参数resolve,reject
new MyPromise((resolve, reject) => {
    setTimeout(() => {
        resolve(1)
    },0)
}).then(value => {
  console.log(value)
})
复制代码

Promise A+ 惟有多写async

// then执行比Promise晚
// reject 拒绝当前服务
// 完善Promise状态 pending ---> fulfilled
// promise.all 全部的promise进行调用 原子操做
// race 只要有一个状态发生变化值就返回
function Promise (fn) {
    var callback;
    this.then = function (done) {
        // callback赋值为回调函数function
        callback = done
    }
    // 先执行resolve
    function resolve (data) {
        setTimeout(function () {
            // 先执行了then,geicallback赋值
            callback(data)
        },0)
    }
    fn(resolve)
}
复制代码

使用函数

new Promise(function (resolve, reject) {
    resolve("解决")
}).then(function (data) {
    console.log(data)
})
复制代码
new Promise(function (resolve, reject) {
    resolve("解决")
    // 不会执行
    setTimeout( () => {
        resolve("解决1")
    }, 2000)
}).then(function (data) {
    console.log(data)
})
// 解决
复制代码
console.log(1)
new Promise(resolve => {
    console.log(2)
    resolve()
    console.log(3)
}).then(() => {
    console.log(4)
})
console.log(5)

// 1 2 3 4 5
复制代码

注意,调用resolvereject并不会终结Promise的参数函数的执行。 上面代码中,调用resolve()后,console.log(3)仍是会执行。 所以,最好在resolvereject前面加上return,这样就不会继续执行了。字体

Promise.prototype.finally() finally方法用于指定无论Promise对象最后状态如何,都会执行的操做。 Promise.all()方法用于将多个Promise实例,包装成一个新的Promise实例。ui

2、Promise.resolve()

Promise.resolve(value)方法返回一个以给定值value解析后的Promise对象。若是该值为promise,返回这个promise;若是这个值是thenable(即带有"then"方法),返回的promise会"跟随"这个thenable的对象,采用它的最终状态;不然返回的promise将以此值完成。此函数将类promise对象的多层嵌套展平。this

Promise.resolve('foo')
  .then(Promise.resolve('bar'))
  .then(function (result) {
      console.log(result)
  })
// foo

var promise1 = Promise.resolve(123);
promise1.then(function(value) {
  console.log(value); // 123
});

// 使用静态Promise.resolve方法
Promise.resolve("Success").then(function(value) {
  console.log(value); // "Success" 此时的状态机为resolve
}, function(value) {
  // 不会被调用
});

// resolve一个数组
var p = Promise.resolve([1,2,3]);
p.then(function(v) {
  console.log(v[0]); // 1
});
复制代码
  • Resolve另外一个promise

此方法和Promise.resolve()嵌套 async await 一个道理spa

var original = Promise.resolve(33)
var cast = Promise.resolve(original)
cast.then(value => {
  console.log('value' + value)
})
console.log('original === cast' + (original === cast))
/*
*  打印顺序以下,这里有一个同步异步前后执行的区别
*  original === cast ? true
*  value: 33
*/
复制代码

从上面的打印结果说明promise嵌套promise以后的值和promise是等价的,所以在KOA2中即便外层嵌套Promise.resolve()但并不影响结果。Promise.resolve()方法是返回resolve的状态机。

// Resolve一个thenable对象
var p1 = Promise.resolve({
    then: function(onFulfill, onReject) { onFulfill("fulfilled!")}
})
console.log(p1 instanceof Promise) // true, 这是一个Promise对象

p1.then(function(v) {
    console.log(v); // 输出"fulfilled!"
}, function(e) {
    // 不会被调用
})

// Thenable在callback以前抛出异常
// Promise rejects
var thenable = { then: function(resolve) {
    throw new TypeError('Throwing')
    resolve("Resolving")
}}

var p2 = Promise.resolve(thenable);
p2.then(function(v) {
  // 不会被调用
}, function(e) {
  console.log(e); // TypeError: Throwing
})

// Thenable在callback以后抛出异常
// Promise resolves
var thenable = { then: function(resolve) {
    resolve("Resolving");
    throw new TypeError("Throwing");
}}

var p3 = Promise.resolve(thenable);
p3.then(function(v) {
  console.log(v); // 输出"Resolving"
}, function(e) {
  // 不会被调用
});
复制代码

3、Promise.all()

Promise.all(iterable)方法返回一个Promise实例,此实例在iterable参数内全部的promise都"完成(resolved)"或参数中不包含promise时回调完成(resolve);若是参数中promise有一个失败(rejected),此实例回调失败(reject),失败缘由的是第一个失败promise的结果。

var promise1 = Promise.resolve(3)
var promise2 = 42
var promise3 = new Promise((resolve, reject) {
   // setTimeout第三个之后的参数是做为第一个func()的参数传进去。
    setTimeout(resolve, 100, 'foo')
}) 

Promise.all([promise1, promise2, promise3]).then((value) {
    console.log(values) // [3, 42, "foo"]
})
复制代码
  • 返回值
  • 若是传入的参数是一个空的可迭代对象,则返回一个已完成(already resolved)状态的Promise
  • 若是传入的参数不包含任何 promise,则返回一个异步完成(asynchronously resolved) Promise。注意:Google Chrome 58 在这种状况下返回一个已完成(already resolved)状态的 Promise
  • 其它状况下返回一个处理中(pending)Promise。这个返回的 promise 以后会在全部的promise 都完成或有一个promise 失败时异步地变为完成或失败。 见下方关于“Promise.all 的异步或同步”示例。返回值将会按照参数内的promise 顺序排列,而不是由调用 promise的完成顺序决定。
// setTimeout
var doc=document.getElementById('div');
setTimeout(function(){
    doc.style.color='red';
},10000,setTimeout(function(){
    doc.style.color='black';
},5000));
复制代码

上面的结果是,div元素内的字体样式5秒后变黑,10秒后再变红。是否是很惊奇,由于第三个参数也是一个定时器,5后就会开启。和JQuery里面的animate()不一样,animate里面回调是执行了前面以后再执行后面的。

说明

  • 此方法在集合多个 promise 的返回结果时颇有用。

  • 完成(Fulfillment: 若是传入的可迭代对象为空,Promise.all 会同步地返回一个已完成(resolved)状态的promise。 若是全部传入的 promise 都变为完成状态,或者传入的可迭代对象内没有 promisePromise.all 返回的 promise 异步地变为完成。 在任何状况下,Promise.all 返回的 promise 的完成状态的结果都是一个数组,它包含全部的传入迭代参数对象的值(也包括非 promise 值)。

  • 失败/拒绝(Rejection: 若是传入的promise中有一个失败(rejected),Promise.all 异步地将失败的那个结果给失败状态的回调函数,而无论其它 promise 是否完成。

  • 实例

  • Promise.all 的使用 若是参数中包含非 promise 值,这些值将被忽略,但仍然会被放在返回数组中(若是 promise 完成的话):

var p = Promise.all([1,2,3]) // Promise { <state>: "fulfilled", <value>: Array[3] }
p.then(v => console.log(v)) // [1, 2, 3]

var p2 = Promise.all([1,2,3, Promise.resolve(444)]) // Promise { <state>: "fulfilled", <value>: Array[4] }

var p3 = Promise.all([1,2,3, Promise.reject(555)]) // Promise { <state>: "rejected", <reason>: 555 }
复制代码
相关文章
相关标签/搜索