浅谈promise

305 阅读3分钟



最近要开始深入学习并巩固前端知识,此文仅以用来记录自己的学习笔记,如有错误请指正. 

首先说说我对promise的了解,

供参考文档:
1. promiseA+

2. 阮一峰日志

1. promise的引出

js中所有代码都是单线程执行的,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行

当达到某个条件时 执行callback

function after(times, callback) {  
    return function () {   
     if (--times === 0) {      callback();    } 
     }}
let eat = after(3, function () {  console.log('ok');});
eat();
eat();


到达规定的时间后 执行callback
function callback() {
    console.log('Done');
}
console.log('before setTimeout()');
setTimeout(callback, 1000); // 1秒钟后调用callback函数
console.log('after setTimeout()');

  • 或者频繁回调

function getData() {    $.ajax({
        url: 'data.json',
        type: 'get',
        success: function (data) {
            review(data);
        }
    });
}


这样写很正常,但是会嵌套回调,而且不太美观.

2. promise 的引出解决了以上问题

  • let fs = require('fs');
    function after(times,callback) {  
    let arr = [];  
    return function (d) {    
    arr.push(d);    if(arr.length === times) callback(arr);  
    }}
    let out = after(2, function (data) {  console.log(data);});
    fs.readFile('a.txt', 'utf8', function (err, data) {  out(data);})


  • 链式调用

    p.then((data)=> {
      console.log(1)
    },(err)=> {
       console.log(2)
    }).then((data)=>{
        console.log('成功')
    },(err)=>{
        console.log('失败')
    })

3. promise的三个状态

  1. resolved(成功态)
  2. rejected(失败态)
  3. pending (未完成)
    状态一旦从pending 状态 执行为resolved或rejected ,状态不会转换, 谁先执行完 ,谁结束这个promise

简单实现一下promise

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError('循环引用'));
  }
  if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    let called;
    try { // 防止取then是出现异常 Object.defineProperty
      let then = x.then; // 取x的then方法 {then:{}}
      if (typeof then === 'function') { // 如果then是函数我就认为它是promise
        // call 第一个参数是this ,后面的是成功的回调和失败的回调
        then.call(x, y => { // 如果y是promise就继续递归解析promise
          if (called) return;
          called = true;
          resolvePromise(promise2, y, resolve, reject);
        }, r => { // 只要失败了就失败了
          if (called) return;
          called = true;
          reject(r);
        });
      } else { // then是一个普通对象,就直接成功即可1
        resolve(x);
      }
    } catch (e) {
      if (called) return;
      called = true;
      reject(e);
    }
  } else { // x = 123
    resolve(x); // x就是一个普通值
  }
}


class Promise {
  constructor(executor) {
    this.status = 'pending';
    this.value = undefined;
    this.reason = undefined;
    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks = [];
    let resolve = (data) => {
      if (this.status === 'pending') {
        this.value = data;
        this.status = 'resolved';
        this.onResolvedCallbacks.forEach(fn => fn());
      }
    }
    let reject = (reason) => {
      if (this.status === 'pending') {
        this.reason = reason;
        this.status = 'rejected';
        this.onRejectedCallbacks.forEach(fn => fn());
      }
    }
    try {
      executor(resolve, reject);
    } catch (e) {
      reject(e);
    }
  }
  then(onFulFilled, onRejected) {
    onFulFilled = typeof onFulFilled === 'function' ? onFulFilled : y => y;
    onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err; };
    let promise2;
    if (this.status === 'resolved') {
      promise2 = new Promise((resolve, reject) => {
        setTimeout(() => {
          try {
            let x = onFulFilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      });
    }
    if (this.status === 'rejected') {
      promise2 = new Promise((resolve, reject) => {
        setTimeout(() => {
          try {
            let x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e);
          }
        }, 0);
      });
    }
    if (this.status === 'pending') {
      promise2 = new Promise((resolve, reject) => {
        this.onResolvedCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onFulFilled(this.value);
              resolvePromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e);
            }
          }, 0)
        });
        // 存放失败的回调
        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onRejected(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0);
        });
      })
    }
    return promise2; // 调用then后返回一个新的promise
  }
  // catch接收的参数 只用错误
  catch(onRejected) {
    // catch就是then的没有成功的简写
    return this.then(null, onRejected);
  }
}
Promise.resolve = function (val) {
  return new Promise((resolve, reject) => resolve(val))
}
Promise.reject = function (val) {
  return new Promise((resolve, reject) => reject(val));
}
Promise.race = function (promises) {
  return new Promise((resolve, reject) => {
    for (let i = 0; i < promises.length; i++) {
      promises[i].then(resolve, reject);
    }
  });
}
Promise.all = function (promises) {
  return new Promise((resolve,reject)=>{
    let arr = [];
    let i = 0; // i的目的是为了保证获取全部成功,来设置的索引
    function processData(index,data) {
      arr[index] = data;
      i++;
      if (i === promises.length){
        resolve(arr);
      }
    }
    for(let i = 0;i<promises.length;i++){
      promises[i].then(data=>{
        processData(i,data);
      }, reject);
    }
  })
}
Promise.deferred = Promise.defer = function () {
  let dfd = {};
  dfd.promise = new Promise((resolve, reject) => {
    dfd.resolve = resolve;
    dfd.reject = reject;
  })
  return dfd;
}
module.exports = Promise;Promise.resolve() 返回一个成功的promise

Promise.reject() 返回一个失败的promise

promise.race处理多请求只取最快的 

promise.all 并发调用,当所有Promise 对象都变为完成态或失败态时,回调将被执行。