微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

JS语法: Promise

以下是原生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 秒
});

总结

  1. 运行:错误没有被捕捉(catch )前,后续的then将不会执行。Promise里不 resolve,.then不往下执行。;then里捕捉不到,就是undefined,后续.then仍会执行。
  2. 返回值:new promise里返回值取决于 resolve/reject. 普通函数里取决于return. (resolve了,函数后续的语句仍会执行)
  3. 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 (但是会等都运行完)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐