Promise 是异步编程的一种解决方案:
从语法上讲,promise是一个对象,从它能够获取异步操做的消息;从本意上讲,它是承诺,承诺它过一段时间会给你一个结果。
promise有三种状态: pending(等待态),fulfiled(成功态),rejected(失败态);状态一旦改变,就不会再变。创造promise实例后,它会当即执行。
在实现以前,能够先看一下Promise A plus规范jquery
这里先实现promise最基本的功能:promise建立后当即执行;在then时执行相应的函数;捕获错误当即变成reject态。npm
// promise里只有一个参数,叫executor(执行器) function Promise(executor) { let self = this; self.status = 'pending';//等待态 self.value = undefined;//默认成功的值 self.err = undefined;//默认失败的值 function resolve(value) { if (self.status === 'pending') { self.status = 'resolved'; self.value = value; } } function reject(err) { if (self.status === 'pending') { self.status = 'rejected'; self.err = err; } } try {//捕获时发生异常,直接变成reject态,抛出错误 executor(resolve, reject);//promise实例建立后,当即执行 } catch (error) { reject(error); } } //在prototype上定义then实例方法 Promise.prototype.then = function (onFulfilled, onRejected) { let self = this; if (self.status === 'resolved') { onFulfilled(self.value); } if (self.status === 'rejected') { onRejected(self.err); } }
这里咱们先测试一下咱们的Promise编程
这里便实现了基本功能,前面说过Promise 是异步编程的一种解决方案;
咱们加个异步逻辑运行一下:数组
咱们都知道异步代码并不会当即执行,这时既不是resolved也不是rejected,而是 pending。
在以前的状态判断里面,正好丢了一个pending状态。OK,这时须要在then里判断当status为pending时,先将onFulfilled, onRejected存入数组里,当status改变时,再遍历数组让里面的函数依次执行,看代码。
(1)申明两个存放onFulfiled,onRejected的数组promise
function Promise(resolver) { let self = this; self.status = 'pending';//等待态 self.value = undefined;//默认成功的值 self.err = undefined;//默认失败的值 self.onResolvedCallbacks = []; // 存放then成功的回调 self.onRejectedCallbacks = []; // 存放then失败的回调 function resolve(value) { if (self.status === 'pending') { self.status = 'resolved'; self.value = value; self.onResolvedCallbacks.forEach(fn=>{//调用resolve时,依次执行数组里的函数 fn(); }) } } function reject(err) { if (self.status === 'pending') { self.status = 'rejected'; self.err = err; self.onRejectedCallbacks.forEach(fn=>{ fn(); }) } } try {//捕获时发生异常,直接抛出错误 resolver(resolve, reject);//promise实例建立后,当即执行它的方法 } catch (error) { reject(error) } }
(2)接着在then方法里添加pending的判断异步
Promise.prototype.then = function (onFulfilled, onRejected) { let self = this; if (self.status === 'resolved') { onFulfilled(self.value); } if (self.status === 'rejected') { onRejected(self.err); } if(self.status==='pending'){// 此时没resolved,也没rejectd self.onResolvedCallbacks.push(()=>{ onFulfilled(self.value); }); self.onRejectedCallbacks.push(()=>{ onRejected(self.err); }) } }
再看刚刚的异步逻辑异步编程
1s后就执行成功了,是否是很神奇,再看下面:函数
(1)规范里说在同一个promise里then能够被屡次调用。测试
(2)jquery能实现链式调用靠的是返回this,而promise不能返回this,规范里又说它返回的是一个新的Promise实例(注意,不是原来那个Promise实例);ui
在then里新建一个promise2并为每个状态包一个Promise
写到这里,再来看看规范,规范里说道
(1)x多是一个promise;
(2)多是一个对象或者方法;
(3)也有多是一个普通的值。
这时须要一个方法来处理x
因而引入一个处理方法resolvePromise(promise2, x, resolve, reject);
这里须要注意一下,有些人写的promise可能会既调用成功,又调用失败,若是两个都调用先调用谁另外一个就忽略掉。
因而增长一个判断called表示是否调用过成功或者失败,看代码:
function resolvePromise(promise2, x, resolve, reject) { if (promise2 === x) {//promise2和x不能相同 return reject(new TypeError('循环引用了')) } let called;// 表示是否调用过成功或者失败 //这里对x的类型进行判断 if (x !== null && (typeof x === 'object' || typeof x === 'function')) { try { // 判断x是否是promise,若是x是对象而且x的then方法是函数咱们就认为他是一个promise let then = x.then; if (typeof then === 'function') { then.call(x, function (y) { if (called) return called = true // y可能仍是一个promise,在去解析直到返回的是一个普通值 resolvePromise(promise2, y, resolve, reject) }, function (err) { //失败 if (called) return called = true reject(err); }) } else { resolve(x) } } catch (e) { if (called) return called = true; reject(e); } } else { // 说明是一个普通值1 resolve(x); // 表示成功了 } }
相应的将前面的代码进行一些更改
若是在then中什么都不传,值会穿透到最后调用的时候;
这时须要在then里给onFulfilled和onRejected写一个默认的函数
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (value) { return value; } onRejected = typeof onRejected === 'function' ? onRejected : function (err) { throw err;//这里须要抛出错误,不能return err,不然会在下一次调用成功态 }
规范里要求,全部的onFulfilled和onRejected都要确保异步执行
这里以resolve为例,写一个setTimeout():
在使用promise的过程当中,咱们都须要先new Promise(),好比说:
function read() { let fs = require('fs'); let promise = new Promise(function(resolve,reject){ fs.readFile('./1.txt','utf8',function(err,data){ if(err) reject(err); resolve(data); }) }); return promise }
在Promise中,它为咱们提供了一个语法糖Promise.defer,用Promise.defer只需这样写:
function read() { let defer = Promise.defer() require('fs').readFile('.//1.txt', 'utf8', function (err, data) { if(err) defer.reject(err); defer.resolve(data); }) return defer.promise; }
为此,再为咱们的Promise加一个defer方法:
Promise.defer = Promise.deferred = function () { let dfd = {}; dfd.promise = new Promise(function (resolve, reject) { dfd.resolve = resolve; dfd.reject = reject; }); return dfd }
在这里,咱们基本实现了一个比较完整的promise;固然Promise还有许多静态方法,还有js的异步发展史,这些能够在下一次进行讨论。
完整代码:
// promise里只有一个参数,叫executor(执行器) function Promise(executor) { let self = this; self.status = 'pending';//等待态 self.value = undefined;//默认成功的值 self.err = 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(err) { if (self.status === 'pending') { self.status = 'rejected'; self.err = err; self.onRejectedCallbacks.forEach(function (fn) { fn(); }); } } try {//捕获时发生异常,直接变成reject态,抛出错误 executor(resolve, reject);//promise实例建立后,当即执行 } catch (error) { reject(error); } } function resolvePromise(promise2, x, resolve, reject) { if (promise2 === x) {//promise2和x不能相同 return reject(new TypeError('循环引用了')) } let called;// 表示是否调用过成功或者失败 //这里对x的类型进行判断 if (x !== null && (typeof x === 'object' || typeof x === 'function')) { try { // 判断x是否是promise,若是x是对象而且x的then方法是函数咱们就认为他是一个promise let then = x.then; if (typeof then === 'function') { then.call(x, function (y) { if (called) return called = true // y可能仍是一个promise,在去解析直到返回的是一个普通值 resolvePromise(promise2, y, resolve, reject) }, function (err) { //失败 if (called) return called = true reject(err); }) } else { resolve(x) } } catch (e) { if (called) return called = true; reject(e); } } else { // 说明是一个普通值1 resolve(x); // 表示成功了 } } //在prototype上定义then实例方法 Promise.prototype.then = function (onFulfilled, onRejected) { onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (value) { return value; } onRejected = typeof onRejected === 'function' ? onRejected : function (err) { throw err;//这里须要抛出错误,不能return err,不然会在下一次调用成功态 } let self = this; let promise2; //返回的promise if (self.status === 'resolved') { promise2 = new Promise(function (resolve, reject) { setTimeout(function () { try { let x = onFulfilled(self.value); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }) }) } if (self.status === 'rejected') { promise2 = new Promise(function (resolve, reject) { setTimeout(function () { try { let x = onRejected(self.err); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }) }) } // 当调用then时可能没成功 也没失败 if (self.status === 'pending') { promise2 = new Promise(function (resolve, reject) { // 此时没有resolve 也没有reject self.onResolvedCallbacks.push(function () { setTimeout(function () { try { let x = onFulfilled(self.value); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e) } }) }); self.onRejectedCallbacks.push(function () { setTimeout(function () { try { let x = onRejected(self.err); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }) }); }) } return promise2; } Promise.defer = Promise.deferred = function () { let dfd = {}; dfd.promise = new Promise(function (resolve, reject) { dfd.resolve = resolve; dfd.reject = reject; }); return dfd } module.exports = Promise;
npm i -g promises-aplus-tests promises-aplus-tests Promise.js