비동기 Javascript 함수를 동기적으로 호출
우선, 이것은 비동기 콜을 수천 회선의 매우 동기적인 코드 베이스로 수정하기 위해 의도적으로 잘못된 방법으로 실행하는 매우 구체적인 경우입니다.또, 현재는, 「적절하게 한다」라고 하는 변경을 실시할 수 없습니다.그것은 내 모든 존재의 섬유를 아프게 하지만 현실과 이상은 종종 일치하지 않는다.이거 짜증나는 거 알아
자, 그럼 어떻게 하면 다음을 할 수 있을까요?
function doSomething() {
var data;
function callBack(d) {
data = d;
}
myAsynchronousCall(param1, callBack);
// block here and return data when the callback is finished
return data;
}
예(또는 그 결여)는 모두 라이브러리나 컴파일러를 사용하고 있습니다만, 이 솔루션에서는 모두 사용할 수 없습니다.UI를 동결하지 않고 차단(예를 들어 콜백이 호출될 때까지 doSomething 함수를 남기지 않음)하는 구체적인 예가 필요합니다.만약 JS에서 그런 것이 가능하다면.
'올바른 방법' 같은 건 말하지 마'
네, 알겠습니다.
"어떻게 하면 그것을 차단할 수 있는지 구체적인 예가 필요합니다.UI를 동결하지 않고.JS에서 그런 일이 가능하다면요.
아니요, UI를 차단하지 않고 실행 중인 JavaScript를 차단하는 것은 불가능합니다.
수 의 옵션은 콜 을 몇 을 설정하는 입니다.data
전 세계에.
function doSomething() {
// callback sets the received data to a global var
function callBack(d) {
window.data = d;
}
// start the async
myAsynchronousCall(param1, callBack);
}
// start the function
doSomething();
// make sure the global is clear
window.data = null
// start polling at an interval until the data is found at the global
var intvl = setInterval(function() {
if (window.data) {
clearInterval(intvl);
console.log(data);
}
}, 100);
것은 로 하고 있습니다.doSomething()
그럴 것 같진 않은데
수 왜을 안doSomething()
다른 콜백에서 전화를 받아야 하는데, 문제가 생기기 전에 그만두는 게 좋겠어요.;)
오, 젠장.올바르게 실시할 수 있는 예를 제시했으므로, 그 해결책을 제시하겠습니다.
function doSomething( func ) {
function callBack(d) {
func( d );
}
myAsynchronousCall(param1, callBack);
}
doSomething(function(data) {
console.log(data);
});
되어 있기 를 에 입니다.doSomething()
콜백에서 호출됩니다.
하고 패스해 .func
★★★★★★★★★★★…
myAsynchronousCall(param1, func);
ES2017의 기능인 비동기 함수는 약속(특정 형식의 비동기 코드) 및 비동기 코드를 사용하여 비동기 코드를 동기화합니다.await
키워드를 지정합니다., 키워드 「」해 주세요.async
function
비동기 또는 비동기 기능을 나타내는 키워드.await
는, 「」가 되어 있는 한 하지 않습니다async
키워드를 지정합니다.현재는 예외는 없기 때문에, 톱 레벨은 기능하지 않습니다(톱 레벨은 기능외의 대기).톱 레벨에 대한 제안도 있습니다만.
ES2017은 2017년 6월 27일에 JavaScript 표준으로 승인되었습니다(즉, 최종 승인).비동기 wait는 이미 브라우저에서 작동할 수 있지만, 그렇지 않은 경우에도 babel이나 traceur와 같은 Javascript 트랜스필러를 사용하여 기능을 사용할 수 있습니다.Chrome 55는 비동기 기능을 완전히 지원합니다.따라서 새로운 브라우저가 있으면 아래 코드를 시험해 볼 수 있습니다.
브라우저 호환성은 kangax의 es2017 호환성 표를 참조하십시오.
'비동기 대기함수'가doAsync
으로부터의 각 합니다.
function timeoutPromise (time) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(Date.now());
}, time)
})
}
function doSomethingAsync () {
return timeoutPromise(1000);
}
async function doAsync () {
var start = Date.now(), time;
console.log(0);
time = await doSomethingAsync();
console.log(time - start);
time = await doSomethingAsync();
console.log(time - start);
time = await doSomethingAsync();
console.log(time - start);
}
doAsync();
wait 키워드를 약속 값 앞에 배치하면(이 경우 약속 값은 doSomethingAsync 함수에 의해 반환되는 값) wait 키워드는 함수 호출 실행을 일시 중지하지만 다른 함수는 일시 중지하지 않고 약속이 해결될 때까지 다른 코드를 계속 실행합니다.약속이 해결되면 약속의 가치가 풀리고, 이제 그 풀리지 않은 가치로 대체되는 대기 및 약속 표현을 생각할 수 있습니다.
따라서 wait는 일시정지 후 값을 언랩한 후 나머지 회선을 실행하기 때문에 다음 예시와 같이 루프 및 내부 함수 호출에 사용할 수 있습니다.이 예에서는 어레이에서 대기하는 시간차를 수집하여 어레이를 출력합니다.
function timeoutPromise (time) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(Date.now());
}, time)
})
}
function doSomethingAsync () {
return timeoutPromise(1000);
}
// this calls each promise returning function one after the other
async function doAsync () {
var response = [];
var start = Date.now();
// each index is a promise returning function
var promiseFuncs= [doSomethingAsync, doSomethingAsync, doSomethingAsync];
for(var i = 0; i < promiseFuncs.length; ++i) {
var promiseFunc = promiseFuncs[i];
response.push(await promiseFunc() - start);
console.log(response);
}
// do something with response which is an array of values that were from resolved promises.
return response
}
doAsync().then(function (response) {
console.log(response)
})
비동기 함수 자체는 약속을 반환하기 때문에 위와 같은 체인을 사용하거나 다른 비동기 대기 함수 내에서 약속을 사용할 수 있습니다.
위의 함수는 Promise를 동시에 사용할 수 있도록 요청을 전송하려면 다른 요청을 전송하기 전에 각 응답을 기다립니다.모든 것.
// no change
function timeoutPromise (time) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(Date.now());
}, time)
})
}
// no change
function doSomethingAsync () {
return timeoutPromise(1000);
}
// this function calls the async promise returning functions all at around the same time
async function doAsync () {
var start = Date.now();
// we are now using promise all to await all promises to settle
var responses = await Promise.all([doSomethingAsync(), doSomethingAsync(), doSomethingAsync()]);
return responses.map(x=>x-start);
}
// no change
doAsync().then(function (response) {
console.log(response)
})
약속이 거부될 수 있는 경우 이를 try catch로 래핑하거나 try catch를 건너뛰고 오류가 비동기/대기 함수에 전파되도록 할 수 있습니다.특히 Node.js에서 약속 오류를 처리하지 않도록 주의해야 합니다.에러의 구조를 나타내는 예를 다음에 나타냅니다.
function timeoutReject (time) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
reject(new Error("OOPS well you got an error at TIMESTAMP: " + Date.now()));
}, time)
})
}
function doErrorAsync () {
return timeoutReject(1000);
}
var log = (...args)=>console.log(...args);
var logErr = (...args)=>console.error(...args);
async function unpropogatedError () {
// promise is not awaited or returned so it does not propogate the error
doErrorAsync();
return "finished unpropogatedError successfully";
}
unpropogatedError().then(log).catch(logErr)
async function handledError () {
var start = Date.now();
try {
console.log((await doErrorAsync()) - start);
console.log("past error");
} catch (e) {
console.log("in catch we handled the error");
}
return "finished handledError successfully";
}
handledError().then(log).catch(logErr)
// example of how error propogates to chained catch method
async function propogatedError () {
var start = Date.now();
var time = await doErrorAsync() - start;
console.log(time - start);
return "finished propogatedError successfully";
}
// this is what prints propogatedError's error.
propogatedError().then(log).catch(logErr)
여기에 가면 ECMAScript 버전에 대한 완성된 제안서를 볼 수 있습니다.
ES2015(ES6)만으로 사용할 수 있는 다른 방법은 발전기 기능을 감싸는 특수 기능을 사용하는 것입니다. 제너레이터 함수에는 wait 키워드를 주변 함수와 함께 복제하기 위해 사용할 수 있는 yield 키워드가 있습니다. yield 키워드와 generator 함수는 훨씬 더 일반적인 목적으로 비동기 대기 함수의 기능보다 더 많은 작업을 수행할 수 있습니다. 비동기 복제에 사용할 수 있는 제너레이터 함수 래퍼를 원하시면 co.js를 체크하겠습니다. 그런데 co의 함수는 비동기 대기 함수와 마찬가지로 약속을 반환합니다. 사실 현시점에서는 브라우저의 호환성은 제너레이터 함수와 비동기 함수 모두 거의 같기 때문에 비동기 대기 기능만 사용하려면 co.js 없이 비동기 함수를 사용해야 합니다(위 스트리커로우가 지원되는 대부분의 환경에서 비동기/await만 사용하는 것이 좋습니다).
현재 IE를 제외한 모든 주요 현재 브라우저(Chrome, Safari 및 Edge)에서 비동기 기능(2017년 기준)에 대한 브라우저 지원은 상당히 양호합니다.
JQuery의 약속:
http://api.jquery.com/promise/
http://api.jquery.com/jQuery.when/
http://api.jquery.com/deferred.promise/
코드를 리팩터링합니다.
var dfd = new jQuery.지연(); 함수 callBack(데이터) {dfd.debug(데이터); } // 비동기 콜을 실행합니다. myAsynchronousCall(param1, callBack); 함수 doSomething(데이터) {// 데이터로 작업... } $.when(dfd).그러면(doSomething);
노드에서 비동기 JavaScript를 강제로 실행할 수 있습니다.sync-rpc와 동기하는 JS.
UI는 확실히 정지하기 때문에, 숏컷을 선택할 수 있는 것은 아직 부정적입니다.JavaScript에서 One Only Thread를 일시 중단할 수 없습니다(NodeJS에서 스레드를 차단할 수 있는 경우도 있습니다).약속이 해결될 때까지 콜백, 이벤트, 비동기 등은 전혀 처리할 수 없습니다.따라서 독자가 OP와 같이 피할 수 없는 상황(또는 내 경우 콜백이나 이벤트 등이 없는 미화된 셸 스크립트를 쓰고 있는 경우 등)이 아니면 이 작업을 수행하지 마십시오.
이 방법은 다음과 같습니다.
./calling-file.js
var createClient = require('sync-rpc');
var mySynchronousCall = createClient(require.resolve('./my-asynchronous-call'), 'init data');
var param1 = 'test data'
var data = mySynchronousCall(param1);
console.log(data); // prints: received "test data" after "init data"
./my-asynchronous-call.js
function init(initData) {
return function(param1) {
// Return a promise here and the resulting rpc client will be synchronous
return Promise.resolve('received "' + param1 + '" after "' + initData + '"');
};
}
module.exports = init;
제한 사항:
두 가지 의식의 입니다.sync-rpc
합니다.것은,, 른른른른른른 른른른른 、require('child_process').spawnSync
:
- 이것은 브라우저에서는 동작하지 않습니다.
- 함수에 대한 인수는 직렬화 가능해야 합니다.당신의 주장은 왕래할 것이다.
JSON.stringify
따라서 프로토타입 체인과 같은 기능 및 확장 불가능한 특성이 손실됩니다.
http://taskjs.org/에 좋은 회피책이 하나 있습니다.
javascript에 새로 추가된 생성기를 사용합니다.따라서 현재 대부분의 브라우저에서는 구현되지 않습니다.파이어폭스에서 테스트했는데, 비동기 함수를 랩하는 좋은 방법입니다.
다음은 프로젝트 GitHub의 코드 예시입니다.
var { Deferred } = task;
spawn(function() {
out.innerHTML = "reading...\n";
try {
var d = yield read("read.html");
alert(d.responseText.length);
} catch (e) {
e.stack.split(/\n/).forEach(function(line) { console.log(line) });
console.log("");
out.innerHTML = "error: " + e;
}
});
function read(url, method) {
method = method || "GET";
var xhr = new XMLHttpRequest();
var deferred = new Deferred();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status >= 400) {
var e = new Error(xhr.statusText);
e.status = xhr.status;
deferred.reject(e);
} else {
deferred.resolve({
responseText: xhr.responseText
});
}
}
};
xhr.open(method, url, true);
xhr.send();
return deferred.promise;
}
네가 원하는 건 이제 가능해서비스 워커에서 비동기 코드를 실행하고 웹 워커에서 동기 코드를 실행할 수 있는 경우 웹 워커가 서비스 워커에게 동기 XHR을 전송하도록 할 수 있습니다.서비스 워커가 비동기 작업을 수행하는 동안 웹 워커의 스레드는 대기합니다.이것은 좋은 방법은 아니지만 효과가 있을 수 있다.
Node.js에서는 실제로 비동기 연산을 호출하는 동기 코드를 작성할 수 있습니다.node-module을 사용하면 가능합니다.NPM 모듈로 제공되는 서드파티 네이티브 확장입니다.파이버/코루틴을 구현하기 위해 특정 파이버가 차단되어 비동기 동작을 대기해도 프로그램 이벤트 루프 전체가 차단되지 않고 다른 파이버(존재하는 경우)가 작업을 계속합니다.
파이버에서는 코드는 다음과 같습니다.
var Fiber = require('fibers');
function doSomething() {
var fiber = Fiber.current;
function callBack(data) {
fiber.run(data);
}
myAsynchronousCall(param1, callBack);
// execution blocks here
var data = Fiber.yield();
return data;
}
// The whole program must be wrapped with Fiber
Fiber(function main() {
var data = doSomething();
console.log(data);
}).run();
「:」를 사용해 주세요.async/await
대신.프로젝트 readme https://github.com/laverdet/node-fibers의 메모를 참조하십시오.
OBSOLEMENCE 메모 - 이 프로젝트의 작성자는 가능하면 사용을 피하는 것이 좋습니다.이 모듈의 원래 버전은 서버의 JavaScript가 크게 달라 보였던 2011년 초에 nodejs v0.1.x를 대상으로 했습니다.그 후 비동기/대기, Promise 및 Generators가 표준화되었고 생태계 전체가 이러한 방향으로 이동했습니다.
가능한 한 새로운 버전의 nodej를 지원할 예정이지만 v8과 nodej는 매우 복잡하고 역동적인 플랫폼입니다.어느 날 이 도서관이 갑자기 작동을 멈추고 아무도 그것에 대해 아무것도 할 수 없게 되는 것은 불가피하다.
섬유 사용자분들께 감사드립니다.여러분들의 지지는 저에게 큰 의미가 있었습니다.
사람들이 고려하지 않을 수 있는 한 가지 사항:비동기 함수(다른 코드 조각에 의존하는 코드 경로)를 제어하고 이 함수가 반드시 비동기일 필요는 없는 경우 옵션 파라미터를 생성하여 (다른 코드 조각을 끊지 않고) 동기화할 수 있습니다.
현재:
async function myFunc(args_etcetc) {
// you wrote this
return 'stuff';
}
(async function main() {
var result = await myFunc('argsetcetc');
console.log('async result:' result);
})()
고려사항:
function myFunc(args_etcetc, opts={}) {
/*
param opts :: {sync:Boolean} -- whether to return a Promise or not
*/
var {sync=false} = opts;
if (sync===true)
return 'stuff';
else
return new Promise((RETURN,REJECT)=> {
RETURN('stuff');
});
}
// async code still works just like before:
(async function main() {
var result = await myFunc('argsetcetc');
console.log('async result:', result);
})();
// prints: 'stuff'
// new sync code works, if you specify sync mode:
(function main() {
var result = myFunc('argsetcetc', {sync:true});
console.log('sync result:', result);
})();
// prints: 'stuff'
물론 비동기 함수가 본질적으로 비동기 조작(네트워크 요구 등)에 의존하고 있는 경우에는 이 방법이 작동하지 않습니다.이 경우 (이유 없이 아이돌 회전을 효과적으로 기다리지 않으면) 노력이 헛수고가 됩니다.
또한 전달된 옵션에 따라 값 또는 약속 중 하나를 반환하는 것은 매우 보기 흉합니다.
('비동기 구성을 사용하지 않았다면 왜 비동기 함수를 작성했을까요?'라고 물을 수 있습니다).아마도 함수의 일부 양식/파라미터는 비동기성을 필요로 하고 다른 것은 그렇지 않을 수 있으며, 코드 복제로 인해 서로 다른 함수의 개별 모듈식 코드 청크가 아닌 단일 블록이 필요했을 것입니다.예를 들어, 아마도 논쟁은 다음 중 하나일 것이다.localDatabase
(기다릴 필요가 없다remoteDatabase
(서양속담, 돈속담) 시 할 수 .{sync:true}
이치노이 시나리오는 다른 문제를 나타내고 있을 가능성이 있습니다만, 이것으로 끝입니다).
Node 16의 워커 스레드를 사용하면 실제로 이를 실현할 수 있습니다.다음 예에서는 워커 스레드가 동기적으로 대기하고 있는 동안 메인 스레드가 비동기 코드를 실행하고 있습니다.
그것은 그다지 유용하지는 않지만, 적어도 비동기 코드를 동기적으로 기다림으로써 원래의 질문에서 막연하게 대답할 수 있다.
const {
Worker, isMainThread, parentPort, receiveMessageOnPort
} = require('worker_threads');
if (isMainThread) {
const worker = new Worker(__filename);
worker.on('message', async () => {
worker.postMessage(await doAsyncStuff());
});
} else {
console.log(doStuffSync());
}
function doStuffSync(){
parentPort.postMessage({fn: 'doStuff'});
let message;
while (!message) {
message = receiveMessageOnPort(parentPort)
}
return message;
}
function doAsyncStuff(){
return new Promise((resolve) => setTimeout(() => resolve("A test"), 1000));
}
이 약속 기능에는 다음과 같은 동기 조작의 2가지 주요 기능이 포함됩니다(또는 ()2개의 콜백을 받아들입니다).결과를 얻으면 resolve()를 호출하여 최종 결과를 전달합니다.오류가 발생하면 reject()를 호출합니다.
이 개념은 결과가 .then() 핸들러의 체인을 통과한다는 것입니다.
const synchronize = (() => {
let chain = Promise.resolve()
return async (promise) => {
return chain = chain.then(promise)
}
})()
let result;
async_function().then(r => result = r);
while (result === undefined) // Wait result from async_function
require('deasync').sleep(100);
콜백으로 변환할 수도 있습니다.
function thirdPartyFoo(callback) {
callback("Hello World");
}
function foo() {
var fooVariable;
thirdPartyFoo(function(data) {
fooVariable = data;
});
return fooVariable;
}
var temp = foo();
console.log(temp);
하는 합니다.
다음 코드는 실행 시 ES6 사양을 지원하는 경우에 사용할 수 있습니다.
비동기 함수에 대한 자세한 정보
async function myAsynchronousCall(param1) {
// logic for myAsynchronous call
return d;
}
function doSomething() {
var data = await myAsynchronousCall(param1); //'blocks' here until the async call is finished
return data;
}
언급URL : https://stackoverflow.com/questions/9121902/call-an-asynchronous-javascript-function-synchronously
'it-source' 카테고리의 다른 글
Python Poety를 Docker (0) | 2023.01.13 |
---|---|
MYSQL: 특정 ID에 대한 다음 100개 및 이전 100개의 ID를 가져옵니다. (0) | 2023.01.13 |
클릭 시 HTML 텍스트 입력의 모든 텍스트 선택 (0) | 2023.01.13 |
왜 2020년 3월 30일과 3월 1일의 차이가 29일이 아닌 28일을 잘못 제공하는가? (0) | 2023.01.13 |
Array.protype.reverse()를 사용하여 Vuejs v-for 무한 업데이트 루프 실행 (0) | 2023.01.13 |