06 Jun 2020
很多人认为setTimeout和setInterval就是JS中的多线程。setTimeout相当于启动一个线程,等待一段时间后执行函数,setInterval则是在另外的一个线程中,每隔一段时间执行函数。 实际上这种观点是错误的。 setTimeout实际上是把函数放入等待队列,等待主线程执行完毕后执行

那么异步Ajax是怎么回事呢?一个常用的开发实践就是发起一个异步的Ajax,界面显示一个进度条样式的Gif,说好的单线程呢?事实上异步>Ajax确实用了多线程,只是Ajax请求的Http连接部分由浏览器另外开了一个线程执行,执行完毕之后给JS引擎发送一个事件,这时候异步请>求的回调代码得以执行。它的执行流程是这样的:
Http请求的执行在另外一个线程中,由于这个线程并不会操作DOM树,所以是可以保证线程安全的。发起Ajax请求和回调函数中间是没有JS执行的,所以页面不会卡死。 作者:ma_fighting 链接:https://www.cnblogs.com/mafeng/p/6292534.html
另外浏览器对于事件的监听也是有单独的线程
我们通过new关键字和Promise构造器创建它的对象。这个构造器接受一个名为”executor function”的函数。这个函数应当接受两个函数参数。当异步任务成功时,第一个函数(resolve)将被调用,并返回一个值代表成功。当其失败时,第二个函数(reject)将被调用,并返回失败原因(失败原因通常是一个error对象)。
例子:
function myAsyncFunction(url) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest() xhr.open("GET", url) xhr.onload = () => resolve(xhr.responseText) xhr.onerror = () => reject(xhr.statusText) xhr.send() }); }作者:MDN docs 链接:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise
源码作者:后盾人教程-向军老师 官网:https://www.houdunren.com/
class HD{
static PENDING = 'pending';
static FUFILLED = 'fulfilled';
static REJECTED = 'rejected';
constructor(executor){
this.status = HD.PENDING;
this.value = null;
this.callbacks = [];
try{
executor(this.resolve.bind(this), this.reject.bind(this));
}catch(error){
this.reject(error);
}
}
resolve(value){
if(this.status === HD.PENDING){
this.status = HD.FUFILLED;
this.value = value;
// this.callbacks.map(callback => {
// })
if(this.callbacks.length !== 0){
setTimeout(() => {
(this.callbacks)[0](this.value);
});
}
}
}
reject(reason){
if(this.status === HD.PENDING){
this.status = HD.REJECTED;
this.value = reason;
if(this.callbacks.length !== 0){
setTimeout(() => {
(this.callbacks)[1](this.value);
});
}
}
}
then(onFufilled, onRejected){
if(typeof onFufilled !== 'function'){
onFufilled = () => {
return this.value;
}
}
if(typeof onRejected !== 'function'){
onRejected = () => this.value;
}
let p = new HD((resolve,reject) =>{
if(this.status === HD.PENDING){
// this.callbacks.push(
// {onFufilled, onRejected}
// )
this.callbacks.push(
value => {
this.parse(p,onFufilled(this.value),resolve,reject);
},
reason => {
this.parse(p,onRejected(this.value),resolve,reject)
}
// console.log(this.callbacks.length)
);
}
if(this.status === HD.FUFILLED){
setTimeout(() => {
this.parse(p,onFufilled(this.value),resolve,reject);
});
}
if(this.status === HD.REJECTED){
setTimeout(() => {
this.parse(p,onRejected(this.value),resolve,reject)
});
}
});
return p;
}
parse(p,result,resolve,reject){
if(p === result){
// console.log(p);
// try {
throw new TypeError('Chaining cycle detected');
// } catch (error) {
// reject(error);
// }
}
try {
if(result instanceof HD){
result.then(resolve,reject);
}else{
resolve(result);
}
} catch (error) {
reject(error);
}
}
static resolve(value){
return new HD((resolve, reject) => {
if(value instanceof HD){
value.then(resolve,reject);
}else{
resolve(value);
}
});
}
static reject(value){
return new HD((resolve, reject) => {
reject(value);
});
}
static all(promises){
return new HD((resolve,reject) => {
const values = []
promises.forEach(promise => {
promise.then(
value => {
values.push(value);
if(values.length === promises.length){
resolve(values);
}
},
reason =>{
reject(reason);
}
);
});
});
}
static race(promises){
return new HD((resolve,reject) => {
promises
});
}
}
// // new Promise((resolve,reject)=>{
// resolve('resolved')
// reject('rejected')
// // })
this.resolve.bind(this)中bind(this)的用处是改变this指向,因为创建promise对象的时候会调用constructor,此时的this即是我们手写的promise对象,会将这个函数的caller指向本次创建的promise对象,如果不bind,resolve函数在当作参数传递时会丢失执行上下文,导致this指向是window而不是promise对象
箭头函数没有this问题,箭头函数可以捕获创建时的this,这里不得不用非匿名函数因为需要后续调用
更多内容可以参考Function.prototype.apply(),Function.prototype.call(),以及箭头函数
如有侵权联系删除
创作不易,感谢支持
比特币-打赏地址:
1DGiAzDacFRxewyos23C14cKcgD5LGZ5hK
狗币-打赏地址:
DRpHTcQXKcauPktjz9WMALST3Vnf5SviDs
以太坊-打赏地址:
0xd34447399c497337a61eccb29cc2ef3e0dad7d13
其他加密货币-打赏地址:
coming soon