真的不能在for循环里resolve完成promise吗
发布于 7 年前 作者 dfsq1311 9186 次浏览 来自 问答
function test() {
  let m = { a: 1, b: 2 };
  let n = {};
  return new Promise(function (resolve) {
    for (let key in m) {
      n[key] = m[key];
      resolve(n)
    }
  })
}

test().then(function (r) {
  console.log(r);
})

输出结果:

{ a: 1, b: 2 }

求解,为何输出不是{a: 1}

10 回复

letconst是 ES6 标准中两个新的用于声明变量的语法。for (let key in m)在 ES5 中可被写为for (var key in m),两者之间的区别只是letvar声明的变量作用域不一样。详细信息可看这里:http://es6.ruanyifeng.com/#docs/let

@leizongmin 还有个问题我不太明白,resolve何时执行?

这是因为: resolve 不能打断 for 循环,当第一次 for 循环里 resolve 了 n,由于 Promise 是异步的,这里没有立即调用 then,会先执行完当前的函数再异步调用 then 的,所以这里会继续执行 for 语句给 n 添加属性。

而当第二次调用 resolve 时,由于 Promise 的规定,resolve 和 reject 两只能调用一次,多次调用只取第一次调用的结果,所有这里第二次调用可以当成无效的。

promise这么用不行,楼主这个需求可以用generator + co (或bluebird的coroutine),也可以用async await

为啥要这样用? 自豪地采用 CNodeJS ionic

因为 promise是异步的,需要在resolve后的下一个tick 才能执行then,除非你加break;或者settimeout,否则for就会执行完成。而你的参数是一个对象,实际是指针,所以结果如你所见的。

试一下这个你就知道了。


function test() {
  let m = { a: 1, b: 2 ,c:3};
  let n = {};
  return new Promise(function (resolve) {
    for (let key in m) {
     if(key!='a'){ 
	 setTimeout(function(){  
	 n[key] = m[key]; 
	 console.log('before resolve',key,Date.now()) 
	 },0); 
	 }
	 else n[key] = m[key]; 
      resolve(n);
    }
  })
}

test().then(function (r) {
  console.log(r,Date.now());
})

使用es6新特性let或者匿名函数自执行就可以了

for (let key in m) {
      n[key] = m[key];
      return resolve(n)
    }

在resolve前加return就可以立即返回,否则会继续执行循环体

你可以去看promise的规范,你可以resolve n次,但是会以第一次的resolve为准,你上面的写法相当于resolve一个引用n次,每次动态改变引用所代表的对象。最后取resolve的第一次的引用,当然是你写的那种了

因为 n 是引用

回到顶部