注意: 状态一旦转换将不可逆, 返回的是一个promise对象,并不是所有都支持promise
Promise.then([onFulfilled], [onRejected])
Promise.catch(onRejected)
Promise.race(iterable)
Promise.all(iterable)
Promise.reslove(obj)
返回一个Promise对象,[[PromiseStatus]]
为resolved,[[PromiseValue]]
为obj,没有就是undefined。Promise.reject(err)
返回一个Promise对象,[[PromiseStatus]]
为rejected,[[PromiseValue]]
为err,没有就是undefined。Promise.finally()
无论resolve还是reject都会触发promises/A+
规范的库promise中then()会放到异步执行事件循环中,所以先往后执行,然后再执行事件循环队列中的。
let promise = new Promise((resolve, reject) => {
console.log(1);
resolve();
console.log(2);
});
promise.then(() => {
console.log("3");
});
console.log(4);
// 1 2 4 3
这里创建了一个Promise对象,然后先打出1,把resolve放入微队列,打出3,then()后放到微队列,然后打出4,再打出2。
let a = new Promise((resolve, reject) => {
console.log(1);
resolve(2);
console.log(3);
})
a.then((res) => {
console.log(res);
})
console.log(4);
//1 3 4 2
promise一旦状态转换是不可逆的,比如说从pending到resolved或者到rejected,而且只能resolve或者reject一次,后面的会被忽略。
let promise = new Promise((resolve, reject) => {
resolve("a");
reject("b");
resolve("c");
});
promise.then((res) => {
console.log("then: ", res);
}).catch((err) => {
console.log("catch: ", err);
})
// then: a
Promise.resolve满足条件接收参数是一个原始值或者不具有then方法的对象,则返回一个新的Promise对象,状态时resolved。而then方法接收的参数是一个函数,所以会被解释成then(null)
Promise.resolve(1).then(2).then(Promise.resolve(3)).then(console.log);
//1
亮灯问题:红灯3秒亮一次,绿灯2秒亮一次,黄灯1秒亮一次,根据楼下已有的代码,实现下!
//红灯3秒亮一次,绿灯2秒亮一次,黄灯1秒亮一次,请开始你的表演!
function red() {
console.log("红灯亮!");
}
function green() {
console.log("绿灯亮!");
}
function yellow() {
console.log("黄灯亮!");
}
第一次看没啥思路,看到秒脑子里反射出定时器,然后应该是递归的因为它没说什么时候停,那第一步实现一个函数传入两个参数一个时间,一个函数,然后多少秒执行这个函数;第二步把具体的秒数对于具体的函数。
//红灯3秒亮一次,绿灯2秒亮一次,黄灯1秒亮一次,请开始你的表演!
function red() {
console.log("红灯亮!");
}
function green() {
console.log("绿灯亮!");
}
function yellow() {
console.log("黄灯亮!");
}
let light = (timer, cb) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
cb();
resolve();
}, timer);
})
};
let gao_light = () => {
Promise.resolve().then(() => {
return light(3000, red);
}).then(() => {
return light(2000, green);
}).then(() => {
return light(1000, yellow);
}).then(() => {
gao_light();
});
};
gao_light();
promise怎么进行流程控制: 实现一个函数,输出如楼下
const timeout = ms => new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, ms);
});
const ajax1 = () => timeout(2000).then(() => {
console.log('1');
return 1;
});
const ajax2 = () => timeout(1000).then(() => {
console.log('2');
return 2;
});
const ajax3 = () => timeout(2000).then(() => {
console.log('3');
return 3;
});
const mergePromise = ajaxArray => {
// please complete coding!
}
mergePromise([ajax1, ajax2, ajax3]).then(data => {
console.log('done');
console.log(data); // [1, 2, 3]
})
如果说按正常执行那么结果肯定不符合期望,一定是要链式的,这样才符合顺序,所以,我们要做的是怎样把它放到一条链上,这里用了等号赋值,其实相当于延长了Promise链式调用。
const timeout = ms => new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, ms);
});
const ajax1 = () => timeout(2000).then(() => {
console.log('1');
return 1;
});
const ajax2 = () => timeout(1000).then(() => {
console.log('2');
return 2;
});
const ajax3 = () => timeout(2000).then(() => {
console.log('3');
return 3;
});
const mergePromise = ajaxArray => {
// please complete coding!
let data = [];
let pr = Promise.resolve();
ajaxArray.forEach(item => {
pr = pr.then(item).then(res => {
data.push(res);
return data;
})
});
return pr;
}
mergePromise([ajax1, ajax2, ajax3]).then(data => {
console.log('done');
console.log('data: ', data); // [1, 2, 3]
})
从宏任务和微任务的角度分析楼下代码的输出:
const first = () => (new Promise((resolve, reject) => {
console.log(3);
let p = new Promise((resolve, reject) => {
console.log(7);
setTimeout(() => {
console.log(5);
resolve(6);
}, 0)
resolve(1);
});
resolve(2);
p.then((arg) => {
console.log(arg);
});
}));
first().then((arg) => {
console.log(arg);
});
console.log(4);
假设程序开始跑了,从最上面我们创建了一个Promise对象,所以先打出7这个没问题,往下走又创建了一个Promise对象,打出7也没问题,发现setTimeout宏任务添加到事件队列,resolve(1)也添加到微任务事件队列,往下走resolve(2)添加到微任务事件队列,然后p.then()和first().then()放入微队列,打出4,然后回去打出1,再打出2,第一轮循环事件结束;然后执行setTimeout打出5,由于Promise状态已经改变,6不打出。
Promise对象先resolve(1),然后接着执行then()方法,在这里我们可以知道会打出1,然后其返回了2,由于不是reject所以catch不到,往下走那么也就是打出2。
Promise.resolve(1).then((res) => {
console.log(res);
return 2;
}).catch((err) => {
console.log(err);
}).then((res) => {
console.log(res);
}) // 1 2
首先创建了一个Promise对象,里面是一个宏任务,第一点我们明确的是打出once再现,然后执行异步任务,注意两次输出的res的值,promise状态只能改变一次所以都是success,但是打出的时间戳差值每台电脑可能不一样的,能肯定的是在1秒后也就是1000+。
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('once');
resolve('success: ');
}, 1000);
})
const start = Date.now();
promise.then((res) => {
console.log(res, Date.now() - start);
})
promise.then((res) => {
console.log(res, Date.now() - start);
})
这题非常好,非常有意思。就是说我们先创建了一个Promise对象p1,里面有个宏任务setTimeout,然后创建了一个基于p1的Promise对象p2。我们先看这个时候p1的状态是pending,那么p2自然也是,所以先打出的是两个pending状态的promise对象,之后两秒后各状态就位,一个resolved,一个rejected!
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success');
}, 1000);
});
const p2 = p1.then(() => {
throw new Error('Error!');
});
console.log('p1: ', p1);
console.log('p2: ', p2);
setTimeout(() => {
console.log('p1: ', p1);
console.log('p2: ', p2);
}, 2000);
这题也很有意思,就是说promise的.then()和.catch()不能返回promise本身,因为会造成死循环。
const promise = Promise.resolve().then(() => {
return promise;
});
promise.catch((err) => {
console.log(err);
});
这题依旧很有意思,process.nextTick()和Promise.then()都属于微任务,而setImmediate属于宏任务,所以这里先打出end,然后执行微任务队列nextTick和then,最后打出setImmediate
process.nextTick(() => {
console.log('nextTick');
});
Promise.resolve().then(() => {
console.log('then');
})
setImmediate(() => {
console.log('setImmediate');
});
console.log('end');
有意思的,我要是catch了多次会是什么样的一个情况,从中可以看出其实它的工作方式像是一个监听器
const promise = new Promise((resolve, reject) => {
reject(Error('我就是试试!'));
});
promise.catch(err => console.error(err));
promise.catch(err => console.error(err));
和楼上做个对比,我要是没有resolve,也没有reject,而是返回了一个新的Promise那么又是如何呢?会打出两次 UnhandledPromiseRejectionWarnin。
const promise = new Promise((resolve, reject) => {
return new Promise((resolve, reject) => {
reject(Error('我就是试试!'));
})
});
promise.catch(err => console.error(err.message));
promise.catch(err => console.error(err.message));
和code12做个对比,这里它只打出一次。可以看到一个Promise对象可以有一个catch,但如果说是一个Promise实例,那它可以进行多次catch。
const promise = new Promise((resolve, reject) => {
reject(Error('我就是试试!'));
}).catch(err => console.error(err.message))
.catch(err => console.error(err.message));
链接:https://segmentfault.com/a/1190000016848192 的题目七
也可以看下这个:https://www.cnblogs.com/xuning/p/8045946.html
参考:https://zhuanlan.zhihu.com/p/29792886
Javascript Promise迷你书:http://liubin.org/promises-book/
《Node.js设计模式》基于ES2015+的回调控制流: https://juejin.im/post/5a17b1cbf265da4324802133
Promises/A+: https://promisesaplus.com/
关于ES6中promise的面试题:https://segmentfault.com/a/1190000016848192
ES6Promise面试题:http://www.bslxx.com/m/view.php?aid=1467
十道ES6的Promise面试题:http://www.bslxx.com/m/view.php?aid=1505
MDN-Promise: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise
Promise 异步流程控制:https://zhuanlan.zhihu.com/p/29792886
MDN-Promise.all() : https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
JavaScript Promises: 9 Questions:https://danlevy.net/javascript-promises-quiz/
阮一峰-Promise对象:http://es6.ruanyifeng.com/#docs/promise
选自《Javascript筑基》系列文章
原文地址:https://github.com/ataola/JavaScript-Tsukuki/blob/master/note/promise-01.md