以下是原生promise,并不好用,setTimeout必须包装在 new promise 中,不然then不会等。
重要:microtask ,microtask确有此事,我的简单实现中state=fulfilled
时,没有异步,因此顺序与系统Promise的不同,按系统自带Promiseresolve中设置state与.then函数运行都在microtask中。
PS:
Promise.then()里面的回调属于 microtask,会在当前 Event Loop 的最后执行,而 SetTimeout 内的回调属于 macrotask,会在下一个 Event Loop 中执行。
第一个then中的两个回调函数决定第一个then返回的是一个什么样的Promise对象。
- 假设第一个then的第一个回调没有返回一个Promise对象,那么第二个then的调用者还是原来的Promise对象,只不过其resolve的值变成了第一个then中第一个回调函数的返回值。
- 假设第一个then的第一个回调函数返回了一个Promise对象,那么第二个then的调用者变成了这个新的Promise对象,第二个then等待这个新的Promise对象resolve或者reject之后执行回调。
话虽然饶了一点,但是我自我感觉说的还是很清楚的呢。哈哈~
如果任意地方遇到了错误,则错误之后交给遇到的第一个带第二个回调函数的then的第二个回调函数来处理。可以理解为错误一直向后reject,直到被处理为止。
另外,Promise对象还有一个方法catch,这个方法接受一个回调函数来处理错误。即:
promise.catch(function(err){
// deal the err.
})
假设对错误的处理是相似的,这个方法可以对错误进行集中统一处理。所以其他的then方法就不需要第二个回调啦~(建议用catch()替代)
// 0.5秒后返回input*input的计算结果:
function multiply(input) {
return new Promise(function (resolve,reject) {
console.log('calculating ' + input + ' x ' + input + '...');
setTimeout(resolve,500,input * input);
});
}
// 0.5秒后返回input+input的计算结果:
function add(input) {
return new Promise(function (resolve,reject) {
console.log('calculating ' + input + ' + ' + input + '...');
setTimeout(resolve,input + input);
});
}
var p = new Promise(function (resolve,reject) {
console.log('start new Promise...');
//(同时reject,resolve. 那个在前边传哪个, 但只能传过去一个。 reject 一般自己不用)
//then,catch 分别用来接收reject/resolve传来的 数据。(但数据流里只会有一个)
//reject(222);
console.log("Have Return?");
resolve(123);
});
p.then(multiply)
.then(add)
.then(multiply)
.then(function(resolve) {console.log(resolve);})
.then(function(){return 1;})
.then(function(res){console.log(res);})
.then(function(res){console.log(res);})
.then(function(){return undif;})
.catch(function(res) {console.log("#" + res);})
.catch(function(res) {console.log("$" + res); return 434;})
.then(function (result) {
console.log('testtests');
console.log('Got value: ' + result);
}).catch(function(res) {console.log(res);})
console.log('test')
reject/ resolve 只能被捕捉一次, 被捕捉后置空。
catch捕捉不到错误,不执行; then捕捉不到,就是undefined,仍会执行。
.then()函数中如果不新建 new promise,普通的函数运行成功 或失败 则覆盖最近的 new promise(成功.then->result 失败.catch->reject)
错误没有被捕捉(catch )前,后续的then将不会执行。
var f = fib(5);
f.next(); // {value: 0,done: false}
f.next(); // {value: 1,done: false}
f.next(); // {value: 2,done: false}
f.next(); // {value: 3,done: true}
next()方法会执行generator的代码,然后,每次遇到yield x;就返回一个对象{value: x,done: true/false},然后“暂停”。返回的value就是yield的返回值,done表示这个generator是否已经执行结束了。如果done为true,则value就是return的返回值。
当执行到done为true时,这个generator对象就已经全部执行完毕,不要再继续调用next()了。
var tic = function(timmer,str){
return new Promise(function(resolve,reject) {
setTimeout(function() {
console.log(str);
resolve(1);
},timmer);
});
};
function *gen(){
yield tic(3000,'red');
yield tic(1000,'green');
yield tic(2000,'yellow');
}
var iterator = gen();
var step = function(gen,iterator){
var s = iterator.next();
if (s.done) {
step(gen,gen());
} else {
s.value.then(function() {
step(gen,iterator);
});
}
}
step(gen,iterator);
例子(重要)
必须返回一个函数给.then啊。
var tic = function(time,fn) {
return function() {
return new Promise((res,rej) => {
setTimeout(() => {fn(); res();},time);
});
}
}
function step() {
d.then(tic(3000,red))
.then(tic(2000,green))
.then(tic(1000,yellow))
.then(tic(3000,yellow));
}
循环输出(坑)
var d = new Promise(function(resolve,reject){resolve();});
var step = function(def) {
while(true) {
def.then(function(){
return tic(3000,red);
}).then(function(){
return tic(2000,green);
}).then(function(){
return tic(1000,yellow);
});
}
}
如果你是这样想的,那么恭喜你成功踩了坑!这道题的第二个考查点就是setTimeout相关的异步队列会挂起知道主进程空闲。如果使用while无限循环,主进程永远不会空闲,setTimeout的函数永远不会执行!
const sign = ['red','green','yellow'];
function tic(str,timer) {
return () => new Promise((res,rej) => {
setTimeout(() => {console.log(str); res();},timer);
});
}
const lamb = sign.reduce(function(prev,item) {
prev.push(tic(item,1000));
return prev;
},[]);
function step() {
new Promise((res) => res()).then(lamb[0]).then(lamb[1]).then(lamb[2]);
step();
}
step(); //RangeError: Maximum call stack size exceeded
例子2
对比,明白区别在哪里。
function red() {
console.log('red');
}
function green() {
console.log('green');
}
function yellow() {
console.log('yellow');
}
var tic = function (timmer,cb) {
return function () {
setTimeout(cb,timmer);
};
};
var d = new Promise(function (resolve,reject) { resolve(); });
var step = function (def) {
def.then(tic(3000,red))
.then(tic(2000,green))
.then(tic(1000,yellow))
.then(tic(3000,yellow));
};
step(d)
resolve与return
res与return返回值
var p = new Promise(function (resolve,reject) {
console.log('-1');
resolve();
return ;
console.log('0');
});
'0'不会输出.
var p = new Promise(function (resolve,reject) {
console.log('-1');
resolve();
console.log('0');
}).then(() => console.log(’3‘));
//-1, 0, 3
’0‘会输出,且在’3‘之前.
res在setTimeout中
var p = new Promise(function (resolve,reject) {
console.log('start new Promise...');
resolve('123');
});
p.then( function(res) {
return new Promise(function(res,rej) {
setTimeout(() => {
console.log('bbbb')
res('first');
},500);
}).then(function(res) {
setTimeout(() => console.log(res),3000);
return "secone";
})
.then(function(res) {
console.log(res+"done");
})
.catch(function(res) {console.log(res);});
})
.then(function(){return undif;})
.catch(function(res) {console.log("#" + res);})
.catch(function(res) {console.log("$" + res); return 434;})
.then(function (result) {
console.log('testtests');
console.log('Got value: ' + result);
}).catch(function(res) {console.log(res);})
输出:
start new Promise...
test
bbbb
seconedone
#ReferenceError: undif is not defined
testtests
Got value: undefined
first
res在setTimeout外
p.then( function(res) {
return new Promise(function(res,rej) {
setTimeout(() => {
console.log('bbbb')
},500);
res('first');
}).then(function(res) {
setTimeout(() => console.log(res),3000);
return "secone";
})
.then(function(res) {
console.log(res+"done");
})
.catch(function(res) {console.log(res);});
})
.then(function(){return undif;})
输出:
start new Promise...
test
seconedone
#ReferenceError: undif is not defined
testtests
Got value: undefined
bbbb
first
注意上面
两例
'bbbb'与'first'输出位置。
var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise((resolve,reject) => {
setTimeout(resolve,100,'foo');
});
Promise.all([p1,p2,p3]).then(values => {
console.log(values); // [3,1337,"foo"]
});
在上面的方法中,promise数组中所有的promise实例都变为
resolve的时候,该方法才会返回,并将所有结果传递results数组中。promise数组中任何一个promise为reject的话,则整个Promise.all调用会立即终止,并返回一个reject的新的promise对象。(数组中几个promise并行的)
实践:
const tasks = [];
const output = function(num) {
return new Promise( (resolve) => {
setTimeout( () => {
console.log(new Date,num);
resolve();
},1000 * num);
})
}
for (var i = 0; i < 5; i++) { // 这里 i 的声明不能改成 let,如果要改该怎么做?
tasks.push(output(i));
}
Promise.all(tasks).then(() => {
setTimeout(() => {
console.log(new Date,i);
},1000); // 注意这里只需要把超时设置为 1 秒
});
总结
- 运行:
错误没有被捕捉(catch )前,后续的then将不会执行。
;Promise里不 resolve,.then不往下执行。
;then里捕捉不到,就是undefined,后续.then仍会执行。 - 返回值:
new promise里返回值取决于 resolve/reject.
普通函数里取决于return. (resolve了,函数后续的语句仍会执行) -
promise不应该出现return
.
promise里可以用 return. 放在resolve前,相当于没有resolve,放在resolve后不起返回值的作用。
var p = new Promise(function (resolve,reject) {
console.log('0');
return 1;
resolve('123');
});
4 new Promise里的函数会立即执行.
先执行完该函数(即使resolve已经执行过,但函数还是要执行完)
new Promise(function executor(resolve) {
console.log(2);
for( var i=0 ; i<10000 ; i++ ) {
i == 9999 && resolve();
}
console.log(3);
}).then(function() {
console.log(4);
});
console.log(5);
//output:
2
3
5
4
5 promise与setTimeout 的先后
(一句话说不清)
Promise.then()里面的回调属于 microtask,会在下一个 Event Loop 中执行。
var p = new Promise(function (resolve,reject) {
console.log('-1');
resolve();
console.log('0');
});
setTimeout(function() {console.log('1')},0);
p.then( function(res) {
console.log('2');
return new Promise(function(res,rej) {
//setTimeout(() => {
//console.log('3')
res('first');
//},500);
console.log('4');
}).then(function(res) {
setTimeout(() => console.log("5"),3000);
})
.then(function(res) {
console.log("6");
})
.catch(function(res) {console.log(res);});
})
.then(function(){console.log('7')})
console.log('8');
//-1,8,2,4,6,7,1,5 (目前代码)
//-1,3,5 (去掉三行注释)
上例中看出,.then会等promise,外面的setTimeout不会等(和我无关啊)。
var p = new Promise(function (resolve,0);
p.then( function(res) {
console.log('2');
var d = new Promise(function(res,3000);
})
.then(function(res) {
console.log("6");
})
.catch(function(res) {console.log(res);});
return 1;
})
.then(function(){console.log('7')})
console.log('8');
//-1,5 (目前代码)
根据上例子(注意没有return promise,只是运算,所以后面的即外部的then不等),好好理解
假设第一个then的第一个回调函数返回了一个Promise对象,那么第二个then的调用者变成了这个新的Promise对象
.(自己的then等自己)(也就是说不return Promise,then不会等
)
循环resolve
new Promise(function (res,rej) {
setTimeout(function () {
for (let i = 0; i < 10; ++i) {
res(i);
}
},1000);
}).then(function (res) {
console.log(res);
})
//0 (但是会等都运行完)
原文链接:https://www.f2er.com/note/422020.html