同步for循环执行和promise
for(let a = 0;a<1000;a++){
new Promise((resolve,reject)=>{
resolve("123")
}).then(res=>{
console.log("异步任务",res)
})
console.log("同步",a)
}
执行结果:
事件循环:当我们的代码从上到下同步执行时,遇到setTimeout就记时,当时间到时就把此事件放到事件队列中,遇到微任务就把微任务放到微任务空间,代码会继续向下执行,直到同步代码执行完毕。
完毕后,会看看微任务空间中有没有微任务,有就把微任务空间中的微任务全部执行,然后去队列中取我们的事件执行,执行时若有微任务继续放到微任务空间,当此事件执行完毕,还会把微任务空间中的微任务全部执行完毕,然后再去取队列中的异步任务。。。。反复循环
如果希望得到一个 Promise 对象,比较方便的方法就是直接调用Promise.resolve()方法。
const p = Promise.resolve('Hello');
p.then(function (s) {
console.log(s)
});
setTimeout(function () {
console.log('three');
}, 0);
Promise.resolve().then(function () {
console.log('two');
});
console.log('one');
//one
//two
//three
上面代码中,setTimeout(fn, 0)在下一轮“事件循环”开始时执行,Promise.resolve()在本轮“事件循环”结束时执行,console.log(‘one’)则是立即执行,因此最先输出。
setTimeout为什么会在Promise之后执行?
查看(宏任务、微任务 event loop)阮一峰版本
知乎的版本
思否的版本
首先输出的是Promise。然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以resolved最后输出。
function timeout(ms){
return new Promise((resolve,reject)=>{
setTimeout(resolve,ms,'done')
console.log("1")
})
};
timeout(0).then((value)=>{
console.log(value)
});
function test(name){
console.log(name);
}
test('2')
//1
//2
//done
then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数。
let promise = new Promise((resolve,reject)=>{
return resolve("123")
})
promise.then(res=>{
console.log(res)
return res
}).then(value=>{
console.log('value:',value)
return value;
}).then(next=>{
console.log('next:',next)
})
//123
//value: 123
//next: 123
p1是一个 Promise,3 秒之后变为rejected。p2的状态在 1 秒之后改变,resolve方法返回的是p1。由于p2返回的是另一个 Promise,导致p2自己的状态无效了,由p1的状态决定p2的状态。所以,后面的then语句都变成针对后者(p1)。又过了 2 秒,p1变为rejected,导致触发catch方法指定的回调函数
let p1 = new Promise(function(resolve,reject){
console.log(1)
setTimeout(()=> reject(new Error('fail')),3000);
console.log(3)
})
let p2 = new Promise((resolve,reject)=>{
console.log(2)
setTimeout(()=>resolve(p1),1000)
})
p2.then(res=>{
console.log(res)
}).catch(err=>{
console.error(err)
})
setTimeout(()=>{
console.log(4)
},2999)
setTimeout(()=>{
console.log(5)
},3001)
//1
//3
//2
//4
//fail
//5
多个异步调用
getJSON("/post/1.json").then(function(post) {
return getJSON(post.commentURL);
}).then(function (comments) {
console.log("resolved: ", comments);
}, function (err){
console.log("rejected: ", err);
});
等同于
getJSON("/post/1.json").then(
post => getJSON(post.commentURL)
).then(
comments => console.log("resolved: ", comments),
err => console.log("rejected: ", err)
);
Promise.all()
javascriptconst p = Promise.all([p1, p2, p3]);
p的状态由p1、p2、p3决定,分成两种情况。
(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
let p1 = new Promise((resolve,reject)=>{
return resolve(1)
});
let p2 = new Promise((resolve,reject)=>{
return reject(2)
})
let p = Promise.all([p1,p2]);
p.then(([r1,r2])=>{
console.log(r1,r2)
}).catch(err=>{
console.log(err)
})
//2
let p1 = new Promise((resolve,reject)=>{
return resolve(1)
});
let p2 = new Promise((resolve,reject)=>{
return resolve(2)
})
let p = Promise.all([p1,p2]);
p.then(([r1,r2])=>{
console.log(r1,r2)
}).catch(err=>{
console.log(err)
})
//1 2
Promise.race()
哪个先执行,返回哪个结果
let p1 = new Promise((resolve,reject)=>{
return resolve(1)
});
let p2 = new Promise((resolve,reject)=>{
return reject(2)
})
//Promise.race();
const p = Promise.race([p1,p2,
new Promise(function(resolve,reject){
setTimeout(()=>{
reject('time out')
},2000)
})
])
p.then(res=>{
console.log('resolve',res)
}).catch(err=>{
console.log('reject',err)
})
// resolve 1
当遇到一个未知函数时,即不知道是同步函数还是异步函数,但想通过promise的then/catch执行后续操作
const f = () => console.log('now');
Promise.resolve().then(f);
console.log('next');
// next
// now
上面写法的缺点:如果f是同步函数,那么它会在本轮事件循环的末尾执行。
解决以上问题
方法一:
(async () => f())()
.then(...)
.catch(...)
方法二:
const f = () => console.log('now');
(
() => new Promise(
resolve => resolve(f())
)
)();
console.log('next');
// now
// next
//等同于
const f = () => console.log('now');
Promise.try(f);
console.log('next');
// now
// next
源码解析:
function Promise (executor) {
var self = this;
self.status = 'pending';
self.value;
self.reason;
self.onResolvedCallbacks = []; // 存放所有成功的回调。
self.onRejectedCallbacks = []; // 存放所有失败的回调。
function resolve(value) {
if (self.status === 'pending') {
self.status = 'resolved';
self.value = value;
self.onResolvedCallbacks.forEach(function (fn) {
fn();
})
}
}
function reject(reason) {
if (self.status === 'pending') {
self.status = 'rejected';
self.reason = reason;
self.onRejectedCallbacks.forEach(function (fn) {
fn();
})
}
}
try {
executor(resove, reject);
} catch (e) {
reject(e);
}
}
function resolvePromise (promise2, x, resolve, reject) {
if (promise2 === x) { // 防止自己等待自己
return reject(new TypeError('循环引用了'));
}
let called; // 表示Promise有没有被调用过
// x是object或者是个function
if ((x !== null && typeof x === 'object') || typeof x === 'function') {
try {
let then = x.then;
if (typeof then === 'function') {
then.call(x, function (y) {
if (called) { // 是否调用过
return;
}
called = true;
resolvePromise (promise2, y, resolve, reject)
}, function (r) {
if (called) { // 是否调用过
return;
}
called = true;
reject(r);
});
} else { // 当前then是一个普通对象。
resolve(x)
}
} catch (e) {
if (called) { // 是否调用过
return;
}
called = true;
reject(e);
}
} else {
if (called) { // 是否调用过
return;
}
called = true;
resolve(x);
}
}
Primsie.prototype.then = function(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (data) { return data;};
onRejected = typeof onRejected === 'function' ? onRejected : function (err) { throw err;};
var self = this;
const promise2 = new Promise(function (resolve, reject) {
if (self.status === 'resolved') {
setTimeout(function() {
try {
const x = onFulfilled(self.value);
resolvePromise(promise2, x, resolve, reject);
} catch(e) {
reject(e);
}
}, 0)
}
if (self.status === 'rejected') {
setTimeout(function() {
try {
const x = onRejected(self.reason);
resolvePromise(promise2, x, resolve, reject);
} catch(e) {
reject(e);
}
}, 0)
}
if (self.status === 'pending') {
self.onResolvedCallbacks.push(function () {
setTimeout(function() {
try {
const x = onFulfilled(self.value);
resolvePromise(promise2, x, resolve, reject);
} catch(e) {
reject(e);
}
}, 0)
});
self.onRejectedCallbacks.push(function() {
setTimeout(function() {
try {
const x = onRejected(self.reason);
resolvePromise(promise2, x, resolve, reject);
} catch(e) {
reject(e);
}
}, 0)
});
}
})
return promise2;
}