promise && Event Loop
Event Loop
事件环
- 宏任务 setImmediate setTimeout MessageChannel
- 微任务 promise.then
- js执行顺序 先把栈里面的东西全部执行, 遇到异步(不管宏任务和微任务)等 等待的时间到了将他们放置 各自的队列中,等栈执行完成后,将所有的微任务执行完成(情况微任务)
- 执行栈的时候 取第一个 放到栈中执行 然后就开始循环 这个就叫Event Loop
进程
- 计算机分配任务的最小单位
- 进程里包含着线程
线程
js是单线程(主线程是单线程)
堆 放对象
栈 存放变量 js值栈中执行的
队列 和 栈
- 队列 先进先出(数组里的pop和push)
- 栈 后进先出(数组里的unshift和shift)
promise实现
- promise是前端处理异步非常好的方式,先实现一个简单版本的
简单版
function Promise(executor){
let self = this;
self.status = 'pending'
self.rs = ''
this.onResolvecb = []
this.onRejectcb = []
function resolve(value){
if(self.status === 'pending'){
self.status = 'resolved'
self.rs = value
self.onResolvecb.forEach(item=>{
item(self.rs)
})
}
}
function reject(reason){
if(self.status === 'pending'){
self.status = 'rejected'
self.rs = reason
self.onRejectcb.forEach(item=>{
item(self.rs)
})
}
}
executor(resolve,reject)
}
Promise.prototype.then = function(onFulfilled,onRejected){
let self = this;
if(self.status === 'resolved'){
onFulfilled(self.rs)
}
if(self.status === 'rejected'){
onRejected(self.rs)
}
if(self.status === 'pending'){
self.onResolvecb.push(onFulfilled)
self.onRejectcb.push(onRejected)
}
}
module.exports = Promise
- 用法
let Promise = require('./promise.js')
let p = new Promise((resolve,reject)=>{
// setTimeout(()=>{
// reject('222')
// },1000)
// console.log('start')
resolve('111')
})
- 当new的时候,会触发
executor函数,当前默认是有三个状态pending,resolved,rejected。首次进来默认是pending,看new的时候调用的谁,分三种情况。第一个触发resolve,状态会变成resolved。第二个触发reject,状态会变成rejected.第三个是异步的时候状态保持pending。同步情况下调用谁,状态就会变化(状态不可逆),获取传递进来的参数,保存到rs上面,等调用then的时候在回传rs的结果。在异步情况下先走then在执行executor函数。在then中状态肯定是pending,然后我们将当前then里面的函数全部保存起来(分onFulfilled,onRejected两种),等待异步时间到了,执行executor函数,看触发resolve还是reject,不管触发谁,他们里面都会执行遍历数组执行,也是就在then时候保存的方法,这样异步也打到了回调,这样我们就实现了一个简易版的promise
配上链式
- 对上面代码修改 实现then的链式
function Promise(executor){
let self = this;
self.status = 'pending'
self.rs = ''
this.onResolvecb = []
this.onRejectcb = []
function resolve(value){
if(self.status === 'pending'){
self.status = 'resolved'
self.rs = value
self.onResolvecb.forEach(item=>{
item()
})
}
}
function reject(reason){
if(self.status === 'pending'){
self.status = 'rejected'
self.rs = reason
self.onRejectcb.forEach(item=>{
item()
})
}
}
executor(resolve,reject)
}
Promise.prototype.then = function(onFulfilled,onRejected){
onFulfilled = typeof onFulfilled == 'function' ? onFulfilled : function (value) {
return value
};
onRejected = typeof onRejected == 'function' ? onRejected : function (value) {
throw value
};
let self = this;
let promise2 = new Promise((resolve,reject)=>{
if(self.status === 'resolved'){
try{
let x = onFulfilled(self.rs)
resolve(x)
}catch(err){
reject(err)
}
}
if(self.status === 'rejected'){
try{
let x = onRejected(self.rs)
resolve(x)
}catch(err){
reject(err)
}
}
if(self.status === 'pending'){
self.onResolvecb.push(function(){
try{
let x = onFulfilled(self.rs)
resolve(x)
}catch(err){
reject(err)
}
})
self.onRejectcb.push(function(){
try{
let x = onRejected(self.rs)
resolve(x)
}catch(err){
reject(err)
}
})
}
})
return promise2
}
module.exports = Promise
- 用法
let Promise = require('./promise.js')
let p = new Promise((resolve,reject)=>{
// setTimeout(()=>{
// reject('222')
// },1000)
// console.log('start')
resolve('111')
})
let p1 = p.then((data)=>{
console.log('success',data)
throw '123'
// return '11as'
},(data)=>{
console.log('err',data)
})
.then()
.then((data)=>{
console.log(data)
},(err)=>{
console.log(err)
})
- 首先我看 then接收的两方法,
onFulfilled和onRejected。用法里面then()可以是空,所以我们要对他们做判断,是一个函数就返回自己,否则的话我们就返回一个函数将获取到的值丢出去,注意成功是return,错误用thorw抛出。因为是链式可以一直调用then,肯定涉及到了递归,所以创建一个Promise实例。将onFulfilled和onRejected直接的结果 传递给resolve值方便下一次拿用 。加入try catch只要有异常就走reject
resolvePromise方法&&完整版
- resolvePromise是处理 resolve返回的promise而不是基本数据类型,这里面逻辑判断稍微麻烦一点。
function Promise(executor) {
let self = this;
self.status = 'pending'
self.rs = ''
this.onResolvecb = []
this.onRejectcb = []
function resolve(value) {
if (self.status === 'pending') {
self.status = 'resolved'
self.rs = value
self.onResolvecb.forEach(item => {
item()
})
}
}
function reject(reason) {
if (self.status === 'pending') {
self.status = 'rejected'
self.rs = reason
self.onRejectcb.forEach(item => {
item()
})
}
}
try{ // 处理在new的时候 报错
executor(resolve, reject)
}catch(err){
reject(err)
}
}
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('循环引用'));
}
let then, called;// called用来防止不规范的promise 表示当前有没有被调用 类似之前的pending
// 判断x是一个引用类型 当前我们的promise是object 判断function是兼容别人写的promise
if (x != null && ((typeof x == 'object' || typeof x == 'function'))) {
try { // try 防止在取then的时候出异常 then里面 可能有getter
then = x.then; // 这里也是防止getter 获取一次 进行处理
if (typeof then == 'function') {
then.call(x, function (y) { //y有可能还是一个promise 要进行递归 一直解析 直到结果是一个常量
if (called)return; // 给别人的promise增加的逻辑 如果没调用过 就是 fasle 直接拦截掉
called = true;
resolvePromise(promise2, y, resolve, reject);
}, function (r) {
if (called)return; // 如果没调用过 就是 fasle 直接拦截掉
called = true;
reject(r);
});
} else {
resolve(x);
}
} catch (e) {
if (called)return; // 如果失败了 就不能在掉成功
called = true;
reject(e);
}
} else {
resolve(x);
}
}
Promise.prototype.then = function (onFulfilled, onRejected) {
let self = this;
// 判断是处理 值的穿透
onFulfilled = typeof onFulfilled == 'function' ? onFulfilled : function (value) {
return value
};
// throw 要在代码快里面
onRejected = typeof onRejected == 'function' ? onRejected : function (value) {
throw value
};
let promise2 = new Promise((resolve, reject) => {
if (self.status === 'resolved') {
setTimeout(() => { //这里的定时器 是为了拿到当前创建的promise2
try {
let x = onFulfilled(self.rs)
// resolve(x)
resolvePromise(promise2,x,resolve,reject)
} catch (err) {
reject(err)
}
})
}
if (self.status === 'rejected') {
setTimeout(() => {
try {
let x = onRejected(self.rs)
// resolve(x)
resolvePromise(promise2,x,resolve,reject)
} catch (err) {
reject(err)
}
})
}
if (self.status === 'pending') {
self.onResolvecb.push(function () {
setTimeout(() => {
try {
let x = onFulfilled(self.rs)
resolvePromise(promise2,x,resolve,reject)
// resolve(x)
} catch (err) {
reject(err)
}
})
})
self.onRejectcb.push(function () {
setTimeout(() => {
try {
let x = onRejected(self.rs)
resolvePromise(promise2,x,resolve,reject)
// resolve(x)
} catch (err) {
reject(err)
}
})
})
}
})
return promise2
}
Promise.prototype.catch = function (err){
return this.then(null,err)
};
Promise.reject = function(data){
return new Promise((resolve,reject)=>{
reject(data)
})
}
Promise.resolve = function(data){
return new Promise((resolve,reject)=>{
resolve(data)
})
}
Promise.prototype.finally = function(cb){
return this.then((data)=>{
return Promise.resolve(cb()).then(()=>data)
},(reason)=>{
return Promise.resolce(cb()).then(()=>{
throw data
})
})
}
Promise.all = function(promises){
return new Promise((resolve,reject)=>{
let rs = []
let index=0;
function processData(data){
index++;
rs.push(data)
if(index==promises.length){
resolve(rs)
}
}
for(let i=0;i<promises.length;i++){
promises[i].then(data=>{
processData(data)
},reject)
}
})
}
Promise.race = function(promises){
return new Promise((resolve,reject)=>{
promises.forEach(item=>{
item.then(data=>{
resolve(data)
})
})
})
}
// 实现一个延迟对象 Promise.deferred别名用来测试的
Promise.defer = Promise.deferred = function(){
let dfd = {}
dfd.promise = new Promise((resolve,reject)=>{
dfd.resolve = resolve
dfd.reject = reject
})
return dfd
}
module.exports = Promise
- resolvePromise 只有当x是引用类型的时候 才会发生回调。第一步先处理异常情况,x.then执行返回可能报异常的时候,这时我们用
try catch处理,出异常直接走reject结束。第二步为什么要多加异步 then = x.then 而不是下面直接使用x.then,为了确保出现getter 里面多次取值出问题,x.then保证了当前的值是同一份。第三步判断then类型是函数,大致可以说明是返回的是promise,否则就是基本数据类型直接出去,这里是后面发生递归的出口。执行他用call修改this执行,指向当前的x,成功的时候获取的y还有可能是promise,此时发生递归 把获取的值传递过去resolvePromise(promise2, y, resolve, reject),失败的时候 直接调用reject。里面有一个called,是防止使用别人不规范的promise,表示当前有没有被调用 类似之前的pending - npm install -g promises-aplus-tests 测试的包 promises-aplus-tests promise.js