承诺的解决范围

问题描述 投票:0回答:1

我正在调用第三方库函数。它返回结果(来自其api)和一个回调函数,我可以为下一组结果调用该函数。

为了简单起见,我创建了一个模拟的第三方函数。

我的问题是,为什么resolve在第一次之后就没有兑现承诺。我猜想是因为resolve的范围是第三方库的内部函数之内。

我该如何解决?有没有更好的方法来实现这一目标?

// Third party function, I cannot control
function thirdParty(callback) {

  var number = 0;

  var inner = function() {
    setTimeout(function() {
      next = inner;
      number = number + 10;
      callback(number, next);
    }, 1000);
  };

  inner();
}

// Code I can control
var nextFunc = null;

// Calls third party api
function getNumber() {
  return new Promise(function(resolve, reject) {
    if (nextFunc) {
      nextFunc();
    } else {
      thirdParty(function(number, next) {
      	console.log(number);
        nextFunc = next;
        resolve(number);
      });
    }
  });
}

function onButtonClick() {
  getNumber().then(function(number) {
    document.getElementById('ele').innerHTML += number + '<br>';
  });
}
<p>
<button type="button" onClick="onButtonClick();">Get Numbers
</button>
</p>
<p id="ele"></p>
javascript asynchronous es6-promise
1个回答
0
投票

它无法解决,因为nextFunc()最终在first承诺内调用传递给thirdParty()的回调,并再次对该承诺进行了resolve()调用,该承诺已被解决,因此它什么也不做。同时,您永远不会在第二个承诺上呼叫resolve(),因此它永远不会成立。

这里是一种更好的方法,鉴于您的第三方API的局限性(我认为它的接口设计很糟糕),我可以想到的唯一方法:

// Third party function, I cannot control
function thirdParty(callback) {

  var number = 0;

  var inner = function() {
    setTimeout(function() {
      next = inner;
      number = number + 10;
      callback(number, next);
    }, 1000);
  };

  inner();
}

// Code I can control
const numbers = getNumbers();

// Calls third party api
async function* getNumbers() {
  let resolve, next;

  yield new Promise(_resolve => {
    resolve = _resolve;

    thirdParty((number, _next) => {
      console.log(number);
      resolve(number);
      next = _next;
    });
  });

  while (true) {
    yield new Promise(_resolve => {
      resolve = _resolve;
      next();
    });
  }
}

document.querySelector('button').addEventListener('click', () => {
  numbers.next().then(({ value }) => {
    document.getElementById('ele').innerHTML += value + '<br>';
  });
});
<p>
  <button type="button">Get Numbers</button>
</p>
<p id="ele"></p>
© www.soinside.com 2019 - 2024. All rights reserved.