Promise

语义通过Promise对象假装拿到异步请求在未来时间后,返回的值。所以说Promise又是一个容器,用于存储未来返回的值。
关键点Promise是状态管理机。通过状态变化,实现异步回调函数的执行。
关键点Promise将异步请求和回调函数分离开来。
关键点使用resolve函数指针,一旦在异步函数里执行了该函数,就会改变Promise的状态,立即执行then方法里的回调函数。

  1. function timeout(ms) {
  2. return new Promise((resolve, reject) => {
  3. setTimeout(resolve, ms);
  4. })
  5. }
  6. timeout(1000)
  7. .then(() => {
  8. console.log(1);
  9. })
function imageLoad(url) {
  return new Promise((resolve, reject) => {
    //创建一个image元素
    var img = new Image();
    img.src = url;
    resolve(img);
  })
}

imageLoad('https://i2.hdslb.com/bfs/face/337351c343b05f0ee735e0918f88862dc645feea.jpg@96w_96h_1c_1s.webp')
  .then((val) => {
  document.body.appendChild(val);
})
function axios(url) {
  var promise = new Promise((resolve, reject) => {
    var xhr = new XMLHttpRequest();
    xhr.open("get", url, true);
    xhr.send();
    xhr.onload = function () {
      resolve(this.status);
    }
  });            
  return promise;
}

axios('http://localhost:3000/').then((data) => {
  console.log(data);
})

关键点Promise绑定DOM事件只会执行一次回调函数,不会重复执行。因为Promise的状态只会改变一次。

var oDiv = document.getElementsByClassName('div')[0];
var promise = new Promise( (resolve, reject) => {
  oDiv.addEventListener('click', ()=>{
    resolve();
  } ,false)
} ).then(() => {
  console.log(3);
})

关键点状态传递。p2的状态改变,由p1的状态决定。

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(new Error('error'));
  }, 1000);
});
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(p1);
  }, 2000);
});

p2.then((data) => {
  console.log(data);
}).catch((err) => {
  console.log(err);
})

promise.prototype.then( )

关键点then方法里的函数才是需要异步执行的回调函数。而promise实例化对象就是一个对象,用于监听状态的变化,一旦变化执行then方法。

  • then中的回调函数的没有返回值。then( )方法的返回值是Promise对象(resolve状态,容器中的未来值就是undefined)。 ```javascript var promise = new Promise((resolve, reject) => { resolve(1) });

promise .then((val) => { console.log(val); //1 }) .then((val) => { console.log(val); //undefined })


- then中的回调函数的返回值是一个值val时,then( )方法的返回值是Promise对象(resolve状态,容器中的未来值就是val)。
```javascript
var promise = new Promise((resolve, reject) => {
    resolve(1)
});

promise
    .then((val) => {
        console.log(val);   //1
        return 2;
    })
    .then((val) => {
        console.log(val);    //2
    })
  • then中的回调函数的返回值是promise对象,then( )方法的返回值就是这个Promise对象。

    promise.prototype.catch( )

    等同于then的失败的回调的写法。
    关键点promise对象的错误,会一直传递,直到被catch捕获。
    关键点如果没有catch方法,promise对象中的错误是不会被捕获。同时错误不会影响到外部代码,通俗的说法就是“Promise 会吃掉错误”。
    const promise = new Promise((resolve, reject) => {
    setTimeout(()=>{resolve(1)}, 1000);
    })
    .then((res) => console.log(res))
    .catch((err)=> console.log(err))
    

    promise.prototype.all( )

    ```javascript //管理promise对象p1,p2,p3。只有所有的promise实例变成fulfilled状态时,all才会调用then回调函数。 //只有有一个promise状态是reject,就会执行catch const p1 = new Promise((resolve, reject) => { setTimeout(()=>{resolve(1)}, 1000); }) const p2 = new Promise((resolve, reject) => { setTimeout(()=>{resolve(2)}, 2000); }) const p3 = new Promise((resolve, reject) => { setTimeout(()=>{resolve(3)}, 3000); })

const all = Promise.all([p1, p2, p3]); all.then((res) => { console.log(res); //[1,2,3] }).catch()

//解构语法 const all = Promise.all([p1, p2, p3]); all.then(([a, b, c]) => { console.log(a); //1 })

<a name="EDZaS"></a>
## promise.prototype.race( )
管理多个promise对象,但是只会返回第一个改变状态的promise对象的结果。
<a name="js29F"></a>
## promise.prototype.finally( )
不管promise对象的状态是什么,最后都会执行里面的回调函数。
<a name="hnTPa"></a>
## promise.prototype.resolve( )
将一个参数直接转换为fulfilled状态的promise对象。

- 参数是一个promise实例,直接返回这个对象
- 参数是原始值,返回一个新的 Promise 对象,状态为resolved,传递的值就是这个原始值。
- 没有参数。返回一个新的 Promise 对象,状态为resolved。说明可以立即执行then里面的回调函数。

关键点立即resolve()的 Promise 对象,是在本轮“事件循环”(event loop)的结束时执行,而不是在下一轮“事件循环”的开始时。

- 参数是thenable对象。具有then方法的对象
```javascript
const thenable = {
    then: function (resolve, reject) {
      resolve(2)
    }
  }

  const p = Promise.resolve(thenable);
  p.then((res) => {
    console.log(res);
  })

promise.prototype.reject( )

将一个参数直接转换为rejected状态的promise对象。

手写promise

  1. 问题:对于执行器中的如果有异步函数,发现promise.then( )没有执行?

由于事件循环机制,同步代码promise.then( )方法优先执行结束后,才会执行异步回调函数里面的resolve( )语句。

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise {
  constructor(executor) {
    this.status = PENDING;
    this.value = undefined;
    this.reason = undefined;

    let resolve = (value) => {
      if (this.status === PENDING) {
        this.status = FULFILLED;
        this.value = value;
      }
    }

    let reject = (reason) => {
      if (this.status === PENDING) {
        this.status = REJECTED;
        this.reason = reason;
      }
    }

    try {
      executor(resolve, reject)
    } catch (error) {
      reject();
    }
  }

  then(onFulfilled, onRejected) {
    if (this.status === FULFILLED) {
      onFulfilled();
    }
    if (this.status === REJECTED) {
      onRejected();
    }
  }
}
var promise = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve();
  })
});
promise.then(() => {
  console.log('success')
})
  1. 对于异步回调代码,由于事件循环resolve( )要等到所有同步代码执行完再执行,因此then最开始执行的时候肯定处于pending状态。这时then方法不是什么都不做。
    • then方法:异步回调函数push到构造函数的数组里。
    • resolve函数的执行,增加一条语句来执行,收集到的回调函数。

关键点解决回调地狱的方法是将异步回调函数分开来写。由promise内部将分开的代码再组合起来。

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise {
  constructor(executor) {
    this.status = PENDING;
    this.value = undefined;
    this.reason = undefined;
    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks = [];

    let resolve = (value) => {
      if (this.status === PENDING) {
        this.status = FULFILLED;
        this.value = value;
        this.onResolvedCallbacks.forEach(fn => fn());
      }
    }

    let reject = (reason) => {
      if (this.status === PENDING) {
        this.status = REJECTED;
        this.reason = reason;
        this.onRejectedCallbacks.forEach(fn => fn());
      }
    }

    try {
      executor(resolve, reject)
    } catch (error) {
      reject();
    }
  }

  then(onFulfilled, onRejected) {
    if (this.status === FULFILLED) {
      onFulfilled(this.value);
    }
    if (this.status === REJECTED) {
      onRejected(this.value);
    }

    //对于异步代码,then方法会先执行,此时还处于pending状态,先收集依赖,等过段时间执行resolve()时,取出来执行。而不是在then方法里面执行
    if (this.status === PENDING) {
      this.onResolvedCallbacks.push(() => {
        onFulfilled(this.value);
      });
      this.onRejectedCallbacks.push(() => {
        onRejected(this.value);
      })
    }
  }
}

var promise = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve();
  })
});
promise.then(() => {
  console.log('success')
})
  1. promise 的优势在于可以链式调用。在我们使用 Promise 的时候,当 then 函数中 return 了一个值,不管是什么值,我们都能在下一个 then 中获取到,这就是所谓的then 的链式调用。而且,当我们不在 then 中放入参数,例:promise.then().then(),那么其后面的 then 依旧可以得到之前 then 返回的值,这就是所谓的值的穿透

    参考连接

    https://es6.ruanyifeng.com/#docs/promise
    https://zhuanlan.zhihu.com/p/183801144